This study allows us to revisit/renew

  1. Regression modeling
  2. Properties of Least Squares/Fitting “a line”
  3. Multiple observation

Datasets for this study are

  1. The main file: gauge.txt
  2. Supplementary large-scale files: download the following folder Full Resolution Data.zip More information about the supplementary file can be found at http://iabp.apl.washington.edu/data.html as well as http://nsidc.org/data/G00791

Question

The aim of this lab is to provide a simple procedure for converting gain into density when the gauge is in operation. Keep in mind that the experiment was conducted by varying density and measuring the response in gain, but when the gauge is ultimately in use, the snow-pack density is to be estimated from the measured gain.

Setup

df <- read.table('gauge-1wb1wa6-2gpel41.txt', header=TRUE)
df <- df[order(df$density), ]  # Sort from least to greatest density
m <- 9  # Number of distinct block densities
t <- 10  # Number of replicate measurements
#install.packages('L1pack')
#install.packages('quantreg')
#install.packages('ggplot2')
library(L1pack)  # Used for least absolute deviations regression line
library(quantreg)  # Used for quantile regression line
library(ggplot2)
Loading required package: SparseM

Attaching package: ‘SparseM’

The following object is masked from ‘package:base’:

    backsolve

Scenario 1: Fitting

Use the data to fit the gain, or a transformation of gain, to density. Try sketching the least squares line on a scatter plot.

# Plot raw data
title <- 'Density vs. Gain'
x.axis <- expression('Density (g/cm'^3*')')
y.axis <- 'Gain'
x.range <- c(0, .7)
y.range <- c(2.5, 6)
plot(df, main=title, xlab=x.axis, ylab=y.axis, xlim=x.range)

# Take log transformation of response variable (gain)
y.log.axis = 'log(Gain)'
df.log = data.frame(df['density'], log(df['gain']))
plot(df.log, main=title, xlab=x.axis, ylab=y.log.axis, xlim=x.range, ylim=y.range)

# Average replicate measurements
df.log.avg = aggregate(list(gain=df.log$gain), by=list(density=df.log$density), FUN=mean)
plot(df.log.avg, main=title, xlab=x.axis, ylab=y.log.axis, xlim=x.range, ylim=y.range)

# Fit gain to density
least.squares <- lm(gain~density, data=df.log.avg)
lad <- lad(gain~density, data=df.log.avg)
quant <- rq(gain~density, tau=.5, data=df.log.avg)
plot(df.log, main=title, xlab=x.axis, ylab=y.log.axis, xlim=x.range, ylim=y.range)
abline(least.squares, col='red')
abline(lad, col='blue')
abline(quant, col='green')
legend('topright', legend=c('Least Squares Regression Line', 'Least Absolute Deviations Regression Line', '50% Quantile Regression Line'), col=c('red', 'blue', 'green'), lty=1)

c(cor(df.log.avg), summary(least.squares)$r.squared)
[1]  1.0000000 -0.9984469 -0.9984469  1.0000000  0.9968963
least.squares

Call:
lm(formula = gain ~ density, data = df.log.avg)

Coefficients:
(Intercept)      density  
      5.997       -4.606  
lad
Call:
lad(formula = gain ~ density, data = df.log.avg)
Converged in 4 iterations

Coefficients:
 (Intercept)     density 
     5.9850     -4.5935 

Degrees of freedom: 9 total; 7 residual
Scale estimate: 0.06926379 
quant
Call:
rq(formula = gain ~ density, tau = 0.5, data = df.log.avg)

Coefficients:
(Intercept)     density 
   5.985029   -4.593460 

Degrees of freedom: 9 total; 7 residual
# Check conditions for linear regression: linearity, normality of residuals, and constant variability
least.squares.residuals <- data.frame(df.log['density'], df.log['gain'] - rep(predict(least.squares), each=10))
lad.residuals <- data.frame(df.log['density'], df.log['gain'] - rep(predict(lad), each=10))
quant.residuals <- data.frame(df.log['density'], df.log['gain'] - rep(predict(quant), each=10))
title.residuals1 <- 'Residuals of Least Squares Regression Line'
title.residuals2 <- 'Residuals of Least Absolute Deviations Regression Line'
title.residuals3 <- 'Residuals of 50% Quantile Regression Line'
plot(least.squares.residuals$gain, main=title.residuals1, ylab=y.axis)
abline(0, 0, col='red')

plot(lad.residuals$gain, main=title.residuals2, ylab=y.axis)
abline(0, 0, col='blue')

plot(quant.residuals$gain, main=title.residuals3, ylab=y.axis)
abline(0, 0, col='green')

num.bins <- 12
hist(least.squares.residuals$gain, breaks=num.bins, main=title.residuals1, xlab=y.axis, col='red')

hist(lad.residuals$gain, breaks=num.bins, main=title.residuals2, xlab=y.axis, col='blue')

hist(quant.residuals$gain, breaks=num.bins, main=title.residuals3, xlab=y.axis, col='green')

qqnorm(least.squares.residuals$gain, main=paste('Normal Q-Q Plot with', title.residuals1), cex.main=1)
qqline(least.squares.residuals$gain, col='red')

qqnorm(lad.residuals$gain, main=paste('Normal Q-Q Plot with', title.residuals2), cex.main=1)
qqline(lad.residuals$gain, col='blue')

qqnorm(quant.residuals$gain, main=paste('Normal Q-Q Plot with', title.residuals3), cex.main=1)
qqline(quant.residuals$gain, col='green')

Scenario 2: Predicting

Ultimately we are interested in answering questions such as: Given a gain reading of 38.6, what is the density of the snow-pack? Given a gain reading of 426.7, what is the density of the snow-pack? These two numeric values, 38.6 and 426.7, were chosen because they are the average gains for the 0.508 and 0.001 densities, respectively.

# Predictions
PredictLogGain <- function(density)
  predict(least.squares, data.frame(density=density))  # Predict log(gain) using density
PredictDensityLeastSquares <- function(gain) {
  intercept <- coef(least.squares)[[1]]
  slope <- coef(least.squares)[[2]]
  (log(gain) - intercept) / slope  # Predict density using gain
}
PredictDensityLad <- function(gain) {
  intercept <- coef(lad)[[1]]
  slope <- coef(lad)[[2]]
  (log(gain) - intercept) / slope  # Predict density using gain
}
PredictDensityQuant <- function(gain) {
  intercept <- coef(quant)[[1]]
  slope <- coef(quant)[[2]]
  (log(gain) - intercept) / slope  # Predict density using gain
}
# 95% prediction and confidence intervals of log(gain) using density
t <- qt(.975, df=m-2)
mean.density <- mean(df.log.avg$density)
summation <- sum((df.log.avg$density - mean.density) ^ 2)
s2 <- aggregate(list(variance=least.squares.residuals$gain), by=list(density=least.squares.residuals$density), FUN=var)
s.pooled <- sqrt(mean(s2$variance))
center.expr <- quote(center <- PredictLogGain(density))
ci.width.expr <- quote(width <- t * s.pooled * sqrt(1/m + (density-mean.density)^2 / summation))
pi.width.expr <- quote(width <- t * s.pooled * sqrt(1 + 1/m + (density-mean.density)^2 / summation))
LogGainCiLower <- function(density) {
  eval(center.expr)
  eval(ci.width.expr)
  center - width
}
LogGainCiUpper <- function(density) {
  eval(center.expr)
  eval(ci.width.expr)
  center + width
}
LogGainPiLower <- function(density) {
  eval(center.expr)
  eval(pi.width.expr)
  center - width
}
LogGainPiUpper <- function(density) {
  eval(center.expr)
  eval(pi.width.expr)
  center + width
}
# Add bands around least squares line
plot(df.log, main=title, xlab=x.axis, ylab=y.log.axis, xlim=x.range, ylim=y.range)
abline(least.squares, col='red')
ci.col <- 'purple'
pi.col <- 'blue'
symbol <- '-'
size <- 1.5
line.type <- 3
line.width <- 0.7
confidence.intervals <- data.frame(density=df.log.avg$density, lower=LogGainCiLower(df.log.avg$density), upper=LogGainCiUpper(df.log.avg$density))
points(x=confidence.intervals$density, y=confidence.intervals$lower, col=ci.col, pch=symbol, cex=size)
points(x=confidence.intervals$density, y=confidence.intervals$upper, col=ci.col, pch=symbol, cex=size)
lines(x=confidence.intervals$density, y=confidence.intervals$lower, col=ci.col, lty=line.type, lwd=line.width)
lines(x=confidence.intervals$density, y=confidence.intervals$upper, col=ci.col, lty=line.type, lwd=line.width)
prediction.intervals <- data.frame(density=df.log.avg$density, lower=LogGainPiLower(df.log.avg$density), upper=LogGainPiUpper(df.log.avg$density))
points(x=prediction.intervals$density, y=prediction.intervals$lower, col=pi.col, pch=symbol, cex=size)
points(x=prediction.intervals$density, y=prediction.intervals$upper, col=pi.col, pch=symbol, cex=size)
lines(x=prediction.intervals$density, y=prediction.intervals$lower, col=pi.col, lty=line.type, lwd=line.width)
lines(x=prediction.intervals$density, y=prediction.intervals$upper, col=pi.col, lty=line.type, lwd=line.width)
legend('topright', legend=c('Least Squares Regression Line', '95% Confidence Interval Bands', '95% Prediction Interval Bands'), col=c('red', ci.col, pi.col), lty=1)

# 95% prediction and confidence intervals of density using gain
end.points <- c(-1, 3)  # Interval to search the root in
DensityCi <- function(gain) {
  lower <- uniroot(function(density) log(gain) - LogGainCiLower(density), interval=end.points)[[1]]
  upper <- uniroot(function(density) log(gain) - LogGainCiUpper(density), interval=end.points)[[1]]
  c(lower, upper)
}
DensityPi <- function(gain) {
  lower <- uniroot(function(density) log(gain) - LogGainPiLower(density), end.points)[[1]]
  upper <- uniroot(function(density) log(gain) - LogGainPiUpper(density), end.points)[[1]]
  c(lower, upper)
}
# Point and interval estimates for example gain readings
PredictDensityLeastSquares(38.6)  # 38.6 is the average gain for 0.508 density
[1] 0.5089113
PredictDensityLad(38.6)
[1] 0.5076298
PredictDensityQuant(38.6)
[1] 0.5076298
DensityCi(38.6)
[1] 0.5011879 0.5169000
DensityPi(38.6)
[1] 0.4889568 0.5291323
PredictDensityLeastSquares(426.7)  # 426.7 is the average gain for 0.001 density
[1] -0.01276954
PredictDensityLad(426.7)
[1] -0.01546807
PredictDensityQuant(426.7)
[1] -0.01546811
DensityCi(426.7)
[1] -0.024285866 -0.001769193
DensityPi(426.7)
[1] -0.034644666  0.008618629

Scenario 3: Cross-Validation

To check how well your procedure works, omit the set of measurements corresponding to the block of density 0.508, apply your “estimation”/calibration procedure to the remaining data, and provide an interval estimate for the density of a block with an average reading of 38.6. Where does the actual density fall in the interval? Try the same test, for the set of measurements at the 0.001 density.

for (omitted in c(0.508, 0.001)) {
  # Omit measurements corresponding to the specified density
  df.log.omitted = df.log[which(df.log['density'] != omitted), ]
  df.log.avg.omitted <- df.log.avg[which(df.log.avg['density'] != omitted), ]
  
  
  # Redo calculations using modified dataset
  least.squares <- lm(gain~density, data=df.log.avg.omitted)
  
  mean.density <- mean(df.log.avg.omitted$density)
  summation <- sum((df.log.avg.omitted$density - mean.density) ^ 2)
  
  s2 <- aggregate(list(variance=least.squares.residuals$gain), by=list(density=least.squares.residuals$density), FUN=var)
  s.pooled <- sqrt(mean(s2$variance))
  
  ci.width.expr <- quote(width <- t * s.pooled * sqrt(1/(m-1) + (density-mean.density)^2 / summation))
  pi.width.expr <- quote(width <- t * s.pooled * sqrt(1 + 1/(m-1) + (density-mean.density)^2 / summation))
  
  plot(df.log.omitted, main=title, xlab=x.axis, ylab=y.log.axis, xlim=x.range, ylim=y.range)
  abline(least.squares, col='red')
  
  ci.col <- 'purple'
  pi.col <- 'blue'
  symbol <- '-'
  size <- 1.5
  line.type <- 3
  line.width <- 0.7
  
  confidence.intervals <- data.frame(density=df.log.avg.omitted$density, lower=LogGainCiLower(df.log.avg.omitted$density), upper=LogGainCiUpper(df.log.avg.omitted$density))
  points(x=confidence.intervals$density, y=confidence.intervals$lower, col=ci.col, pch=symbol, cex=size)
  points(x=confidence.intervals$density, y=confidence.intervals$upper, col=ci.col, pch=symbol, cex=size)
  lines(x=confidence.intervals$density, y=confidence.intervals$lower, col=ci.col, lty=line.type, lwd=line.width)
  lines(x=confidence.intervals$density, y=confidence.intervals$upper, col=ci.col, lty=line.type, lwd=line.width)
  
  prediction.intervals <- data.frame(density=df.log.avg.omitted$density, lower=LogGainPiLower(df.log.avg.omitted$density), upper=LogGainPiUpper(df.log.avg.omitted$density))
  points(x=prediction.intervals$density, y=prediction.intervals$lower, col=pi.col, pch=symbol, cex=size)
  points(x=prediction.intervals$density, y=prediction.intervals$upper, col=pi.col, pch=symbol, cex=size)
  lines(x=prediction.intervals$density, y=prediction.intervals$lower, col=pi.col, lty=line.type, lwd=line.width)
  lines(x=prediction.intervals$density, y=prediction.intervals$upper, col=pi.col, lty=line.type, lwd=line.width)
  
  legend('topright', legend=c('Least Squares Regression Line', '95% Confidence Interval Bands', '95% Prediction Interval Bands'), col=c('red', ci.col, pi.col), lty=1)
  
  print(PredictDensityLeastSquares(38.6))  # 38.6 is the average gain for 0.508 density
  print(DensityCi(38.6))
  print(DensityPi(38.6))
  
  print(PredictDensityLeastSquares(426.7))  # 426.7 is the average gain for 0.001 density
  print(DensityCi(426.7))
  print(DensityPi(426.7))
}
[1] 0.5091927
[1] 0.5006695 0.5180406
[1] 0.4889184 0.5297925
[1] -0.0128045
[1] -0.024342164 -0.001790802
[1] -0.034760736  0.008598777

[1] 0.5092919
[1] 0.5014370 0.5174323
[1] 0.4890257 0.5298473
[1] -0.02051733
[1] -0.035344991 -0.006521825
[1] -0.044604850  0.002738127

Additional Scenario: Temperature, DOY, and Latitude.

Use the additional dataset to construct a model fitting temperature with DOY, latitude, and other reasonable features. Try sketching the least squares line on a scatter plot. We aim to investigate the relationship between temperature and the DOY, and its latitude.

# Check the correlation
data <- read.csv('Full Resolution Data/64506420.csv', header=TRUE)
data <- data[,c('Hour','DOY','POS_DOY','Lat','Lon','Ts','BP')]
# Drop the extreme outlier case
#data <- data[which(data$Ts>-200),]
data_matrix <- as.matrix(data)
# Correlation Matrix
corr_matrix <- cor(data_matrix)
corr_matrix
                Hour          DOY      POS_DOY          Lat         Lon           Ts          BP
Hour     1.000000000 -0.006779489 -0.006775002 -0.007511024  0.01217860  0.008592576  0.02505819
DOY     -0.006779489  1.000000000  0.999999958  0.903704617 -0.68012490 -0.906918658 -0.17232397
POS_DOY -0.006775002  0.999999958  1.000000000  0.903696909 -0.68013445 -0.906916964 -0.17230481
Lat     -0.007511024  0.903704617  0.903696909  1.000000000 -0.59748962 -0.958835395 -0.29666821
Lon      0.012178596 -0.680124899 -0.680134450 -0.597489620  1.00000000  0.564136723 -0.02981279
Ts       0.008592576 -0.906918658 -0.906916964 -0.958835395  0.56413672  1.000000000  0.20223136
BP       0.025058188 -0.172323969 -0.172304805 -0.296668215 -0.02981279  0.202231363  1.00000000
library(ggplot2)
# Group by DOY and average replicated measurements
data$DOY <- round(data$DOY,0)
data.avg = aggregate(list(data=data[,c('Ts','Lat')]), by=list(DOY=data$DOY), FUN=mean)
# least squares line
ggplot(data.avg,aes(x=data.avg$DOY, y=data.avg$data.Ts)) + 
  geom_point(color='#2980B9', size = 4) + 
  geom_smooth(method=lm, color='#2C3E50') +ggtitle(label ="Least Squares Regression Line") + xlab("Day Of Year") +
  ylab("Temperature")

fit1<-lm(formula = data.Ts ~ DOY, data = data.avg)
summary(fit1)

Call:
lm(formula = data.Ts ~ DOY, data = data.avg)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.95439 -0.34633  0.03139  0.35247  0.84693 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  9.353218   0.114242   81.87   <2e-16 ***
DOY         -0.040253   0.001989  -20.23   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4741 on 86 degrees of freedom
Multiple R-squared:  0.8264,    Adjusted R-squared:  0.8244 
F-statistic: 409.4 on 1 and 86 DF,  p-value: < 2.2e-16
ggplot(data.avg,aes(x=data.avg$data.Lat, y=data.avg$data.Ts)) + 
  geom_point(color='#2980B9', size = 4) + 
  geom_smooth(method=lm, color='#2C3E50') +ggtitle(label ="Least Squares Regression Line")+ xlab("Lattitude") +
  ylab("Temperature")

fit2<-lm(formula = data.Ts ~ data.Lat, data = data.avg)
summary(fit2)

Call:
lm(formula = data.Ts ~ data.Lat, data = data.avg)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.51377 -0.26924 -0.04201  0.24403  0.64902 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  47.9901     1.2672   37.87   <2e-16 ***
data.Lat     -0.6202     0.0193  -32.14   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3155 on 86 degrees of freedom
Multiple R-squared:  0.9231,    Adjusted R-squared:  0.9222 
F-statistic:  1033 on 1 and 86 DF,  p-value: < 2.2e-16
# Polynomial Regression Line
fit3<-lm(formula = data.Ts ~ DOY + data.Lat, data = data.avg)
fit4<-lm(formula = data.Ts ~ data.Lat + DOY, data = data.avg)
summary(fit3)

Call:
lm(formula = data.Ts ~ DOY + data.Lat, data = data.avg)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.60721 -0.22496 -0.00537  0.25822  0.61356 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 40.049638   2.673979  14.978  < 2e-16 ***
DOY         -0.009756   0.002936  -3.322  0.00132 ** 
data.Lat    -0.491566   0.042805 -11.484  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2985 on 85 degrees of freedom
Multiple R-squared:  0.932, Adjusted R-squared:  0.9304 
F-statistic: 582.1 on 2 and 85 DF,  p-value: < 2.2e-16
summary(fit4)

Call:
lm(formula = data.Ts ~ data.Lat + DOY, data = data.avg)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.60721 -0.22496 -0.00537  0.25822  0.61356 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 40.049638   2.673979  14.978  < 2e-16 ***
data.Lat    -0.491566   0.042805 -11.484  < 2e-16 ***
DOY         -0.009756   0.002936  -3.322  0.00132 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2985 on 85 degrees of freedom
Multiple R-squared:  0.932, Adjusted R-squared:  0.9304 
F-statistic: 582.1 on 2 and 85 DF,  p-value: < 2.2e-16
qqnorm(fit2$residuals, main=paste('Normal Q-Q Plot with', title.residuals1), cex.main=1)
qqline(fit2$residuals, col='red')

title.residuals1 <- 'Residuals of Least Square Regression Line'
plot(fit2$residuals, main=title.residuals1, ylab = "Standardized Residuals")
abline(0, 0, col='red')

<<<<<<< HEAD <<<<<<< HEAD
LS0tCnRpdGxlOiAnQ0FTRSBTVFVEWSA0OicKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBzdHVkeSBhbGxvd3MgdXMgdG8gcmV2aXNpdC9yZW5ldwoKMS4gUmVncmVzc2lvbiBtb2RlbGluZwoyLiBQcm9wZXJ0aWVzIG9mIExlYXN0IFNxdWFyZXMvRml0dGluZyAiYSBsaW5lIgozLiBNdWx0aXBsZSBvYnNlcnZhdGlvbgoKRGF0YXNldHMgZm9yIHRoaXMgc3R1ZHkgYXJlCgoxLiBUaGUgbWFpbiBmaWxlOiBnYXVnZS50eHQKMi4gU3VwcGxlbWVudGFyeSBsYXJnZS1zY2FsZSBmaWxlczogZG93bmxvYWQgdGhlIGZvbGxvd2luZyBmb2xkZXIgRnVsbCBSZXNvbHV0aW9uIERhdGEuemlwIE1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHN1cHBsZW1lbnRhcnkgZmlsZSBjYW4gYmUgZm91bmQgYXQgaHR0cDovL2lhYnAuYXBsLndhc2hpbmd0b24uZWR1L2RhdGEuaHRtbCBhcyB3ZWxsIGFzIGh0dHA6Ly9uc2lkYy5vcmcvZGF0YS9HMDA3OTEKCgojIyBRdWVzdGlvbgpUaGUgYWltIG9mIHRoaXMgbGFiIGlzIHRvIHByb3ZpZGUgYSBzaW1wbGUgcHJvY2VkdXJlIGZvciBjb252ZXJ0aW5nIGdhaW4gaW50byBkZW5zaXR5IHdoZW4gdGhlIGdhdWdlIGlzIGluIG9wZXJhdGlvbi4gS2VlcCBpbiBtaW5kIHRoYXQgdGhlIGV4cGVyaW1lbnQgd2FzIGNvbmR1Y3RlZCBieSB2YXJ5aW5nIGRlbnNpdHkgYW5kIG1lYXN1cmluZyB0aGUgcmVzcG9uc2UgaW4gZ2FpbiwgYnV0IHdoZW4gdGhlIGdhdWdlIGlzIHVsdGltYXRlbHkgaW4gdXNlLCB0aGUgc25vdy1wYWNrIGRlbnNpdHkgaXMgdG8gYmUgZXN0aW1hdGVkIGZyb20gdGhlIG1lYXN1cmVkIGdhaW4uCgoKIyMgU2V0dXAKYGBge3J9CmRmIDwtIHJlYWQudGFibGUoJ2dhdWdlLTF3YjF3YTYtMmdwZWw0MS50eHQnLCBoZWFkZXI9VFJVRSkKZGYgPC0gZGZbb3JkZXIoZGYkZGVuc2l0eSksIF0gICMgU29ydCBmcm9tIGxlYXN0IHRvIGdyZWF0ZXN0IGRlbnNpdHkKCm0gPC0gOSAgIyBOdW1iZXIgb2YgZGlzdGluY3QgYmxvY2sgZGVuc2l0aWVzCnQgPC0gMTAgICMgTnVtYmVyIG9mIHJlcGxpY2F0ZSBtZWFzdXJlbWVudHMKCiNpbnN0YWxsLnBhY2thZ2VzKCdMMXBhY2snKQojaW5zdGFsbC5wYWNrYWdlcygicXVhbnRyZWciKQpsaWJyYXJ5KEwxcGFjaykgICMgVXNlZCBmb3IgbGVhc3QgYWJzb2x1dGUgZGV2aWF0aW9ucyByZWdyZXNzaW9uIGxpbmUKbGlicmFyeShxdWFudHJlZykgICMgVXNlZCBmb3IgcXVhbnRpbGUgcmVncmVzc2lvbiBsaW5lCmBgYAoKCiMjIFNjZW5hcmlvIDE6IEZpdHRpbmcKVXNlIHRoZSBkYXRhIHRvIGZpdCB0aGUgZ2Fpbiwgb3IgYSB0cmFuc2Zvcm1hdGlvbiBvZiBnYWluLCB0byBkZW5zaXR5LiBUcnkgc2tldGNoaW5nIHRoZSBsZWFzdCBzcXVhcmVzIGxpbmUgb24gYSBzY2F0dGVyIHBsb3QuCgoqIERvIHRoZSByZXNpZHVhbHMgaW5kaWNhdGUgYW55IHByb2JsZW1zIHdpdGggdGhlIGZpdD8KKiBJZiB0aGUgZGVuc2l0aWVzIG9mIHRoZSBwb2x5ZXRoeWxlbmUgYmxvY2tzIGFyZSBub3QgcmVwb3J0ZWQgZXhhY3RseSwgaG93IG1pZ2h0IHRoaXMgYWZmZWN0IHRoZSBmaXQ/CiogV2hhdCBpZiB0aGUgYmxvY2tzIG9mIHBvbHlldGh5bGVuZSB3ZXJlIG5vdCBtZWFzdXJlZCBpbiByYW5kb20gb3JkZXIgKGxvY2F0aW9uKT8KYGBge3J9CiMgUGxvdCByYXcgZGF0YQp0aXRsZSA8LSAnRGVuc2l0eSB2cy4gR2FpbicKeC5heGlzIDwtIGV4cHJlc3Npb24oJ0RlbnNpdHkgKGcvY20nXjMqJyknKQp5LmF4aXMgPC0gJ0dhaW4nCngucmFuZ2UgPC0gYygwLCAuNykKeS5yYW5nZSA8LSBjKDIuNSwgNikKcGxvdChkZiwgbWFpbj10aXRsZSwgeGxhYj14LmF4aXMsIHlsYWI9eS5heGlzLCB4bGltPXgucmFuZ2UpCgoKIyBUYWtlIGxvZyB0cmFuc2Zvcm1hdGlvbiBvZiByZXNwb25zZSB2YXJpYWJsZSAoZ2FpbikKeS5sb2cuYXhpcyA9ICdsb2coR2FpbiknCmRmLmxvZyA9IGRhdGEuZnJhbWUoZGZbJ2RlbnNpdHknXSwgbG9nKGRmWydnYWluJ10pKQpwbG90KGRmLmxvZywgbWFpbj10aXRsZSwgeGxhYj14LmF4aXMsIHlsYWI9eS5sb2cuYXhpcywgeGxpbT14LnJhbmdlLCB5bGltPXkucmFuZ2UpCgoKIyBBdmVyYWdlIHJlcGxpY2F0ZSBtZWFzdXJlbWVudHMKZGYubG9nLmF2ZyA9IGFnZ3JlZ2F0ZShsaXN0KGdhaW49ZGYubG9nJGdhaW4pLCBieT1saXN0KGRlbnNpdHk9ZGYubG9nJGRlbnNpdHkpLCBGVU49bWVhbikKcGxvdChkZi5sb2cuYXZnLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmxvZy5heGlzLCB4bGltPXgucmFuZ2UsIHlsaW09eS5yYW5nZSkKCgojIEZpdCBnYWluIHRvIGRlbnNpdHkKbGVhc3Quc3F1YXJlcyA8LSBsbShnYWlufmRlbnNpdHksIGRhdGE9ZGYubG9nLmF2ZykKbGFkIDwtIGxhZChnYWlufmRlbnNpdHksIGRhdGE9ZGYubG9nLmF2ZykKcXVhbnQgPC0gcnEoZ2Fpbn5kZW5zaXR5LCB0YXU9LjUsIGRhdGE9ZGYubG9nLmF2ZykKCnBsb3QoZGYubG9nLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmxvZy5heGlzLCB4bGltPXgucmFuZ2UsIHlsaW09eS5yYW5nZSkKYWJsaW5lKGxlYXN0LnNxdWFyZXMsIGNvbD0ncmVkJykKYWJsaW5lKGxhZCwgY29sPSdibHVlJykKYWJsaW5lKHF1YW50LCBjb2w9J2dyZWVuJykKbGVnZW5kKCd0b3ByaWdodCcsIGxlZ2VuZD1jKCdMZWFzdCBTcXVhcmVzIFJlZ3Jlc3Npb24gTGluZScsICdMZWFzdCBBYnNvbHV0ZSBEZXZpYXRpb25zIFJlZ3Jlc3Npb24gTGluZScsICc1MCUgUXVhbnRpbGUgUmVncmVzc2lvbiBMaW5lJyksIGNvbD1jKCdyZWQnLCAnYmx1ZScsICdncmVlbicpLCBsdHk9MSkKCmMoY29yKGRmLmxvZy5hdmcpLCBzdW1tYXJ5KGxlYXN0LnNxdWFyZXMpJHIuc3F1YXJlZCkKbGVhc3Quc3F1YXJlcwpsYWQKcXVhbnQKCgojIENoZWNrIGNvbmRpdGlvbnMgZm9yIGxpbmVhciByZWdyZXNzaW9uOiBsaW5lYXJpdHksIG5vcm1hbGl0eSBvZiByZXNpZHVhbHMsIGFuZCBjb25zdGFudCB2YXJpYWJpbGl0eQpsZWFzdC5zcXVhcmVzLnJlc2lkdWFscyA8LSBkYXRhLmZyYW1lKGRmLmxvZ1snZGVuc2l0eSddLCBkZi5sb2dbJ2dhaW4nXSAtIHJlcChwcmVkaWN0KGxlYXN0LnNxdWFyZXMpLCBlYWNoPTEwKSkKbGFkLnJlc2lkdWFscyA8LSBkYXRhLmZyYW1lKGRmLmxvZ1snZGVuc2l0eSddLCBkZi5sb2dbJ2dhaW4nXSAtIHJlcChwcmVkaWN0KGxhZCksIGVhY2g9MTApKQpxdWFudC5yZXNpZHVhbHMgPC0gZGF0YS5mcmFtZShkZi5sb2dbJ2RlbnNpdHknXSwgZGYubG9nWydnYWluJ10gLSByZXAocHJlZGljdChxdWFudCksIGVhY2g9MTApKQoKdGl0bGUucmVzaWR1YWxzMSA8LSAnUmVzaWR1YWxzIG9mIExlYXN0IFNxdWFyZXMgUmVncmVzc2lvbiBMaW5lJwp0aXRsZS5yZXNpZHVhbHMyIDwtICdSZXNpZHVhbHMgb2YgTGVhc3QgQWJzb2x1dGUgRGV2aWF0aW9ucyBSZWdyZXNzaW9uIExpbmUnCnRpdGxlLnJlc2lkdWFsczMgPC0gJ1Jlc2lkdWFscyBvZiA1MCUgUXVhbnRpbGUgUmVncmVzc2lvbiBMaW5lJwpwbG90KGxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGdhaW4sIG1haW49dGl0bGUucmVzaWR1YWxzMSwgeWxhYj15LmF4aXMpCmFibGluZSgwLCAwLCBjb2w9J3JlZCcpCnBsb3QobGFkLnJlc2lkdWFscyRnYWluLCBtYWluPXRpdGxlLnJlc2lkdWFsczIsIHlsYWI9eS5heGlzKQphYmxpbmUoMCwgMCwgY29sPSdibHVlJykKcGxvdChxdWFudC5yZXNpZHVhbHMkZ2FpbiwgbWFpbj10aXRsZS5yZXNpZHVhbHMzLCB5bGFiPXkuYXhpcykKYWJsaW5lKDAsIDAsIGNvbD0nZ3JlZW4nKQoKbnVtLmJpbnMgPC0gMTIKaGlzdChsZWFzdC5zcXVhcmVzLnJlc2lkdWFscyRnYWluLCBicmVha3M9bnVtLmJpbnMsIG1haW49dGl0bGUucmVzaWR1YWxzMSwgeGxhYj15LmF4aXMsIGNvbD0ncmVkJykKaGlzdChsYWQucmVzaWR1YWxzJGdhaW4sIGJyZWFrcz1udW0uYmlucywgbWFpbj10aXRsZS5yZXNpZHVhbHMyLCB4bGFiPXkuYXhpcywgY29sPSdibHVlJykKaGlzdChxdWFudC5yZXNpZHVhbHMkZ2FpbiwgYnJlYWtzPW51bS5iaW5zLCBtYWluPXRpdGxlLnJlc2lkdWFsczMsIHhsYWI9eS5heGlzLCBjb2w9J2dyZWVuJykKCnFxbm9ybShsZWFzdC5zcXVhcmVzLnJlc2lkdWFscyRnYWluLCBtYWluPXBhc3RlKCdOb3JtYWwgUS1RIFBsb3Qgd2l0aCcsIHRpdGxlLnJlc2lkdWFsczEpLCBjZXgubWFpbj0xKQpxcWxpbmUobGVhc3Quc3F1YXJlcy5yZXNpZHVhbHMkZ2FpbiwgY29sPSdyZWQnKQpxcW5vcm0obGFkLnJlc2lkdWFscyRnYWluLCBtYWluPXBhc3RlKCdOb3JtYWwgUS1RIFBsb3Qgd2l0aCcsIHRpdGxlLnJlc2lkdWFsczIpLCBjZXgubWFpbj0xKQpxcWxpbmUobGFkLnJlc2lkdWFscyRnYWluLCBjb2w9J2JsdWUnKQpxcW5vcm0ocXVhbnQucmVzaWR1YWxzJGdhaW4sIG1haW49cGFzdGUoJ05vcm1hbCBRLVEgUGxvdCB3aXRoJywgdGl0bGUucmVzaWR1YWxzMyksIGNleC5tYWluPTEpCnFxbGluZShxdWFudC5yZXNpZHVhbHMkZ2FpbiwgY29sPSdncmVlbicpCmBgYAoKCiMjIFNjZW5hcmlvIDI6IFByZWRpY3RpbmcKVWx0aW1hdGVseSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBhbnN3ZXJpbmcgcXVlc3Rpb25zIHN1Y2ggYXM6IEdpdmVuIGEgZ2FpbiByZWFkaW5nIG9mIDM4LjYsIHdoYXQgaXMgdGhlIGRlbnNpdHkgb2YgdGhlIHNub3ctcGFjaz8gR2l2ZW4gYSBnYWluIHJlYWRpbmcgb2YgNDI2LjcsIHdoYXQgaXMgdGhlIGRlbnNpdHkgb2YgdGhlIHNub3ctcGFjaz8gVGhlc2UgdHdvIG51bWVyaWMgdmFsdWVzLCAzOC42IGFuZCA0MjYuNywgd2VyZSBjaG9zZW4gYmVjYXVzZSB0aGV5IGFyZSB0aGUgYXZlcmFnZSBnYWlucyBmb3IgdGhlIDAuNTA4IGFuZCAwLjAwMSBkZW5zaXRpZXMsIHJlc3BlY3RpdmVseS4KCiogRGV2ZWxvcCBhIHByb2NlZHVyZSBmb3IgYWRkaW5nIGJhbmRzIGFyb3VuZCB5b3VyIGxlYXN0IHNxdWFyZXMgbGluZSB0aGF0IGNhbiBiZSB1c2VkIHRvIG1ha2UgaW50ZXJ2YWwgZXN0aW1hdGVzIGZvciB0aGUgc25vdy1wYWNrIGRlbnNpdHkgZnJvbSBnYWluIG1lYXN1cmVtZW50cy4gS2VlcCBpbiBtaW5kIGhvdyB0aGUgZGF0YSB3ZXJlIGNvbGxlY3RlZDogc2V2ZXJhbCBtZWFzdXJlbWVudHMgb2YgZ2FpbiB3ZXJlIHRha2VuIGZvciBwb2x5ZW55dGh5bGVuZSBibG9ja3Mgb2Yga25vd24gZGVuc2l0eS4KYGBge3IgZmlnLmFzcD0yLCBmaWcud2lkdGg9NX0KIyBQcmVkaWN0aW9ucwpQcmVkaWN0TG9nR2FpbiA8LSBmdW5jdGlvbihkZW5zaXR5KQogIHByZWRpY3QobGVhc3Quc3F1YXJlcywgZGF0YS5mcmFtZShkZW5zaXR5PWRlbnNpdHkpKSAgIyBQcmVkaWN0IGxvZyhnYWluKSB1c2luZyBkZW5zaXR5CgpQcmVkaWN0RGVuc2l0eUxlYXN0U3F1YXJlcyA8LSBmdW5jdGlvbihnYWluKSB7CiAgaW50ZXJjZXB0IDwtIGNvZWYobGVhc3Quc3F1YXJlcylbWzFdXQogIHNsb3BlIDwtIGNvZWYobGVhc3Quc3F1YXJlcylbWzJdXQogIChsb2coZ2FpbikgLSBpbnRlcmNlcHQpIC8gc2xvcGUgICMgUHJlZGljdCBkZW5zaXR5IHVzaW5nIGdhaW4KfQoKUHJlZGljdERlbnNpdHlMYWQgPC0gZnVuY3Rpb24oZ2FpbikgewogIGludGVyY2VwdCA8LSBjb2VmKGxhZClbWzFdXQogIHNsb3BlIDwtIGNvZWYobGFkKVtbMl1dCiAgKGxvZyhnYWluKSAtIGludGVyY2VwdCkgLyBzbG9wZSAgIyBQcmVkaWN0IGRlbnNpdHkgdXNpbmcgZ2Fpbgp9CgpQcmVkaWN0RGVuc2l0eVF1YW50IDwtIGZ1bmN0aW9uKGdhaW4pIHsKICBpbnRlcmNlcHQgPC0gY29lZihxdWFudClbWzFdXQogIHNsb3BlIDwtIGNvZWYocXVhbnQpW1syXV0KICAobG9nKGdhaW4pIC0gaW50ZXJjZXB0KSAvIHNsb3BlICAjIFByZWRpY3QgZGVuc2l0eSB1c2luZyBnYWluCn0KCgojIDk1JSBwcmVkaWN0aW9uIGFuZCBjb25maWRlbmNlIGludGVydmFscyBvZiBsb2coZ2FpbikgdXNpbmcgZGVuc2l0eQp0IDwtIHF0KC45NzUsIGRmPW0tMikKbWVhbi5kZW5zaXR5IDwtIG1lYW4oZGYubG9nLmF2ZyRkZW5zaXR5KQpzdW1tYXRpb24gPC0gc3VtKChkZi5sb2cuYXZnJGRlbnNpdHkgLSBtZWFuLmRlbnNpdHkpIF4gMikKCnMyIDwtIGFnZ3JlZ2F0ZShsaXN0KHZhcmlhbmNlPWxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGdhaW4pLCBieT1saXN0KGRlbnNpdHk9bGVhc3Quc3F1YXJlcy5yZXNpZHVhbHMkZGVuc2l0eSksIEZVTj12YXIpCnMucG9vbGVkIDwtIHNxcnQobWVhbihzMiR2YXJpYW5jZSkpCgpjZW50ZXIuZXhwciA8LSBxdW90ZShjZW50ZXIgPC0gUHJlZGljdExvZ0dhaW4oZGVuc2l0eSkpCmNpLndpZHRoLmV4cHIgPC0gcXVvdGUod2lkdGggPC0gdCAqIHMucG9vbGVkICogc3FydCgxL20gKyAoZGVuc2l0eS1tZWFuLmRlbnNpdHkpXjIgLyBzdW1tYXRpb24pKQpwaS53aWR0aC5leHByIDwtIHF1b3RlKHdpZHRoIDwtIHQgKiBzLnBvb2xlZCAqIHNxcnQoMSArIDEvbSArIChkZW5zaXR5LW1lYW4uZGVuc2l0eSleMiAvIHN1bW1hdGlvbikpCgpMb2dHYWluQ2lMb3dlciA8LSBmdW5jdGlvbihkZW5zaXR5KSB7CiAgZXZhbChjZW50ZXIuZXhwcikKICBldmFsKGNpLndpZHRoLmV4cHIpCiAgY2VudGVyIC0gd2lkdGgKfQoKTG9nR2FpbkNpVXBwZXIgPC0gZnVuY3Rpb24oZGVuc2l0eSkgewogIGV2YWwoY2VudGVyLmV4cHIpCiAgZXZhbChjaS53aWR0aC5leHByKQogIGNlbnRlciArIHdpZHRoCn0KCkxvZ0dhaW5QaUxvd2VyIDwtIGZ1bmN0aW9uKGRlbnNpdHkpIHsKICBldmFsKGNlbnRlci5leHByKQogIGV2YWwocGkud2lkdGguZXhwcikKICBjZW50ZXIgLSB3aWR0aAp9CgpMb2dHYWluUGlVcHBlciA8LSBmdW5jdGlvbihkZW5zaXR5KSB7CiAgZXZhbChjZW50ZXIuZXhwcikKICBldmFsKHBpLndpZHRoLmV4cHIpCiAgY2VudGVyICsgd2lkdGgKfQoKIyBBZGQgYmFuZHMgYXJvdW5kIGxlYXN0IHNxdWFyZXMgbGluZQpwbG90KGRmLmxvZywgbWFpbj10aXRsZSwgeGxhYj14LmF4aXMsIHlsYWI9eS5sb2cuYXhpcywgeGxpbT14LnJhbmdlLCB5bGltPXkucmFuZ2UpCmFibGluZShsZWFzdC5zcXVhcmVzLCBjb2w9J3JlZCcpCgpjaS5jb2wgPC0gJ3B1cnBsZScKcGkuY29sIDwtICdibHVlJwpzeW1ib2wgPC0gJy0nCnNpemUgPC0gMS41CmxpbmUudHlwZSA8LSAzCmxpbmUud2lkdGggPC0gMC43Cgpjb25maWRlbmNlLmludGVydmFscyA8LSBkYXRhLmZyYW1lKGRlbnNpdHk9ZGYubG9nLmF2ZyRkZW5zaXR5LCBsb3dlcj1Mb2dHYWluQ2lMb3dlcihkZi5sb2cuYXZnJGRlbnNpdHkpLCB1cHBlcj1Mb2dHYWluQ2lVcHBlcihkZi5sb2cuYXZnJGRlbnNpdHkpKQpwb2ludHMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGxvd2VyLCBjb2w9Y2kuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKcG9pbnRzKHg9Y29uZmlkZW5jZS5pbnRlcnZhbHMkZGVuc2l0eSwgeT1jb25maWRlbmNlLmludGVydmFscyR1cHBlciwgY29sPWNpLmNvbCwgcGNoPXN5bWJvbCwgY2V4PXNpemUpCmxpbmVzKHg9Y29uZmlkZW5jZS5pbnRlcnZhbHMkZGVuc2l0eSwgeT1jb25maWRlbmNlLmludGVydmFscyRsb3dlciwgY29sPWNpLmNvbCwgbHR5PWxpbmUudHlwZSwgbHdkPWxpbmUud2lkdGgpCmxpbmVzKHg9Y29uZmlkZW5jZS5pbnRlcnZhbHMkZGVuc2l0eSwgeT1jb25maWRlbmNlLmludGVydmFscyR1cHBlciwgY29sPWNpLmNvbCwgbHR5PWxpbmUudHlwZSwgbHdkPWxpbmUud2lkdGgpCgpwcmVkaWN0aW9uLmludGVydmFscyA8LSBkYXRhLmZyYW1lKGRlbnNpdHk9ZGYubG9nLmF2ZyRkZW5zaXR5LCBsb3dlcj1Mb2dHYWluUGlMb3dlcihkZi5sb2cuYXZnJGRlbnNpdHkpLCB1cHBlcj1Mb2dHYWluUGlVcHBlcihkZi5sb2cuYXZnJGRlbnNpdHkpKQpwb2ludHMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGxvd2VyLCBjb2w9cGkuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKcG9pbnRzKHg9cHJlZGljdGlvbi5pbnRlcnZhbHMkZGVuc2l0eSwgeT1wcmVkaWN0aW9uLmludGVydmFscyR1cHBlciwgY29sPXBpLmNvbCwgcGNoPXN5bWJvbCwgY2V4PXNpemUpCmxpbmVzKHg9cHJlZGljdGlvbi5pbnRlcnZhbHMkZGVuc2l0eSwgeT1wcmVkaWN0aW9uLmludGVydmFscyRsb3dlciwgY29sPXBpLmNvbCwgbHR5PWxpbmUudHlwZSwgbHdkPWxpbmUud2lkdGgpCmxpbmVzKHg9cHJlZGljdGlvbi5pbnRlcnZhbHMkZGVuc2l0eSwgeT1wcmVkaWN0aW9uLmludGVydmFscyR1cHBlciwgY29sPXBpLmNvbCwgbHR5PWxpbmUudHlwZSwgbHdkPWxpbmUud2lkdGgpCgpsZWdlbmQoJ3RvcHJpZ2h0JywgbGVnZW5kPWMoJ0xlYXN0IFNxdWFyZXMgUmVncmVzc2lvbiBMaW5lJywgJzk1JSBDb25maWRlbmNlIEludGVydmFsIEJhbmRzJywgJzk1JSBQcmVkaWN0aW9uIEludGVydmFsIEJhbmRzJyksIGNvbD1jKCdyZWQnLCBjaS5jb2wsIHBpLmNvbCksIGx0eT0xKQoKCiMgOTUlIHByZWRpY3Rpb24gYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIGRlbnNpdHkgdXNpbmcgZ2FpbgplbmQucG9pbnRzIDwtIGMoLTEsIDMpICAjIEludGVydmFsIHRvIHNlYXJjaCB0aGUgcm9vdCBpbgoKRGVuc2l0eUNpIDwtIGZ1bmN0aW9uKGdhaW4pIHsKICBsb3dlciA8LSB1bmlyb290KGZ1bmN0aW9uKGRlbnNpdHkpIGxvZyhnYWluKSAtIExvZ0dhaW5DaUxvd2VyKGRlbnNpdHkpLCBpbnRlcnZhbD1lbmQucG9pbnRzKVtbMV1dCiAgdXBwZXIgPC0gdW5pcm9vdChmdW5jdGlvbihkZW5zaXR5KSBsb2coZ2FpbikgLSBMb2dHYWluQ2lVcHBlcihkZW5zaXR5KSwgaW50ZXJ2YWw9ZW5kLnBvaW50cylbWzFdXQogIGMobG93ZXIsIHVwcGVyKQp9CgpEZW5zaXR5UGkgPC0gZnVuY3Rpb24oZ2FpbikgewogIGxvd2VyIDwtIHVuaXJvb3QoZnVuY3Rpb24oZGVuc2l0eSkgbG9nKGdhaW4pIC0gTG9nR2FpblBpTG93ZXIoZGVuc2l0eSksIGVuZC5wb2ludHMpW1sxXV0KICB1cHBlciA8LSB1bmlyb290KGZ1bmN0aW9uKGRlbnNpdHkpIGxvZyhnYWluKSAtIExvZ0dhaW5QaVVwcGVyKGRlbnNpdHkpLCBlbmQucG9pbnRzKVtbMV1dCiAgYyhsb3dlciwgdXBwZXIpCn0KCgojIFBvaW50IGFuZCBpbnRlcnZhbCBlc3RpbWF0ZXMgZm9yIGV4YW1wbGUgZ2FpbiByZWFkaW5ncwpQcmVkaWN0RGVuc2l0eUxlYXN0U3F1YXJlcygzOC42KSAgIyAzOC42IGlzIHRoZSBhdmVyYWdlIGdhaW4gZm9yIDAuNTA4IGRlbnNpdHkKUHJlZGljdERlbnNpdHlMYWQoMzguNikKUHJlZGljdERlbnNpdHlRdWFudCgzOC42KQpEZW5zaXR5Q2koMzguNikKRGVuc2l0eVBpKDM4LjYpCgpQcmVkaWN0RGVuc2l0eUxlYXN0U3F1YXJlcyg0MjYuNykgICMgNDI2LjcgaXMgdGhlIGF2ZXJhZ2UgZ2FpbiBmb3IgMC4wMDEgZGVuc2l0eQpQcmVkaWN0RGVuc2l0eUxhZCg0MjYuNykKUHJlZGljdERlbnNpdHlRdWFudCg0MjYuNykKRGVuc2l0eUNpKDQyNi43KQpEZW5zaXR5UGkoNDI2LjcpCmBgYAoKCiMjIFNjZW5hcmlvIDM6IENyb3NzLVZhbGlkYXRpb24KVG8gY2hlY2sgaG93IHdlbGwgeW91ciBwcm9jZWR1cmUgd29ya3MsIG9taXQgdGhlIHNldCBvZiBtZWFzdXJlbWVudHMgY29ycmVzcG9uZGluZyB0byB0aGUgYmxvY2sgb2YgZGVuc2l0eSAwLjUwOCwgYXBwbHkgeW91ciAiZXN0aW1hdGlvbiIvY2FsaWJyYXRpb24gcHJvY2VkdXJlIHRvIHRoZSByZW1haW5pbmcgZGF0YSwgYW5kIHByb3ZpZGUgYW4gaW50ZXJ2YWwgZXN0aW1hdGUgZm9yIHRoZSBkZW5zaXR5IG9mIGEgYmxvY2sgd2l0aCBhbiBhdmVyYWdlIHJlYWRpbmcgb2YgMzguNi4gV2hlcmUgZG9lcyB0aGUgYWN0dWFsIGRlbnNpdHkgZmFsbCBpbiB0aGUgaW50ZXJ2YWw/IFRyeSB0aGUgc2FtZSB0ZXN0LCBmb3IgdGhlIHNldCBvZiBtZWFzdXJlbWVudHMgYXQgdGhlIDAuMDAxIGRlbnNpdHkuCmBgYHtyIGZpZy5hc3A9MiwgZmlnLndpZHRoPTV9CmZvciAob21pdHRlZCBpbiBjKDAuNTA4LCAwLjAwMSkpIHsKICAjIE9taXQgbWVhc3VyZW1lbnRzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHNwZWNpZmllZCBkZW5zaXR5CiAgZGYubG9nLm9taXR0ZWQgPSBkZi5sb2dbd2hpY2goZGYubG9nWydkZW5zaXR5J10gIT0gb21pdHRlZCksIF0KICBkZi5sb2cuYXZnLm9taXR0ZWQgPC0gZGYubG9nLmF2Z1t3aGljaChkZi5sb2cuYXZnWydkZW5zaXR5J10gIT0gb21pdHRlZCksIF0KICAKICAKICAjIFJlZG8gY2FsY3VsYXRpb25zIHVzaW5nIG1vZGlmaWVkIGRhdGFzZXQKICBsZWFzdC5zcXVhcmVzIDwtIGxtKGdhaW5+ZGVuc2l0eSwgZGF0YT1kZi5sb2cuYXZnLm9taXR0ZWQpCiAgCiAgbWVhbi5kZW5zaXR5IDwtIG1lYW4oZGYubG9nLmF2Zy5vbWl0dGVkJGRlbnNpdHkpCiAgc3VtbWF0aW9uIDwtIHN1bSgoZGYubG9nLmF2Zy5vbWl0dGVkJGRlbnNpdHkgLSBtZWFuLmRlbnNpdHkpIF4gMikKICAKICBzMiA8LSBhZ2dyZWdhdGUobGlzdCh2YXJpYW5jZT1sZWFzdC5zcXVhcmVzLnJlc2lkdWFscyRnYWluKSwgYnk9bGlzdChkZW5zaXR5PWxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGRlbnNpdHkpLCBGVU49dmFyKQogIHMucG9vbGVkIDwtIHNxcnQobWVhbihzMiR2YXJpYW5jZSkpCiAgCiAgY2kud2lkdGguZXhwciA8LSBxdW90ZSh3aWR0aCA8LSB0ICogcy5wb29sZWQgKiBzcXJ0KDEvKG0tMSkgKyAoZGVuc2l0eS1tZWFuLmRlbnNpdHkpXjIgLyBzdW1tYXRpb24pKQogIHBpLndpZHRoLmV4cHIgPC0gcXVvdGUod2lkdGggPC0gdCAqIHMucG9vbGVkICogc3FydCgxICsgMS8obS0xKSArIChkZW5zaXR5LW1lYW4uZGVuc2l0eSleMiAvIHN1bW1hdGlvbikpCiAgCiAgcGxvdChkZi5sb2cub21pdHRlZCwgbWFpbj10aXRsZSwgeGxhYj14LmF4aXMsIHlsYWI9eS5sb2cuYXhpcywgeGxpbT14LnJhbmdlLCB5bGltPXkucmFuZ2UpCiAgYWJsaW5lKGxlYXN0LnNxdWFyZXMsIGNvbD0ncmVkJykKICAKICBjaS5jb2wgPC0gJ3B1cnBsZScKICBwaS5jb2wgPC0gJ2JsdWUnCiAgc3ltYm9sIDwtICctJwogIHNpemUgPC0gMS41CiAgbGluZS50eXBlIDwtIDMKICBsaW5lLndpZHRoIDwtIDAuNwogIAogIGNvbmZpZGVuY2UuaW50ZXJ2YWxzIDwtIGRhdGEuZnJhbWUoZGVuc2l0eT1kZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSwgbG93ZXI9TG9nR2FpbkNpTG93ZXIoZGYubG9nLmF2Zy5vbWl0dGVkJGRlbnNpdHkpLCB1cHBlcj1Mb2dHYWluQ2lVcHBlcihkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSkpCiAgcG9pbnRzKHg9Y29uZmlkZW5jZS5pbnRlcnZhbHMkZGVuc2l0eSwgeT1jb25maWRlbmNlLmludGVydmFscyRsb3dlciwgY29sPWNpLmNvbCwgcGNoPXN5bWJvbCwgY2V4PXNpemUpCiAgcG9pbnRzKHg9Y29uZmlkZW5jZS5pbnRlcnZhbHMkZGVuc2l0eSwgeT1jb25maWRlbmNlLmludGVydmFscyR1cHBlciwgY29sPWNpLmNvbCwgcGNoPXN5bWJvbCwgY2V4PXNpemUpCiAgbGluZXMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGxvd2VyLCBjb2w9Y2kuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKICBsaW5lcyh4PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGRlbnNpdHksIHk9Y29uZmlkZW5jZS5pbnRlcnZhbHMkdXBwZXIsIGNvbD1jaS5jb2wsIGx0eT1saW5lLnR5cGUsIGx3ZD1saW5lLndpZHRoKQogIAogIHByZWRpY3Rpb24uaW50ZXJ2YWxzIDwtIGRhdGEuZnJhbWUoZGVuc2l0eT1kZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSwgbG93ZXI9TG9nR2FpblBpTG93ZXIoZGYubG9nLmF2Zy5vbWl0dGVkJGRlbnNpdHkpLCB1cHBlcj1Mb2dHYWluUGlVcHBlcihkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSkpCiAgcG9pbnRzKHg9cHJlZGljdGlvbi5pbnRlcnZhbHMkZGVuc2l0eSwgeT1wcmVkaWN0aW9uLmludGVydmFscyRsb3dlciwgY29sPXBpLmNvbCwgcGNoPXN5bWJvbCwgY2V4PXNpemUpCiAgcG9pbnRzKHg9cHJlZGljdGlvbi5pbnRlcnZhbHMkZGVuc2l0eSwgeT1wcmVkaWN0aW9uLmludGVydmFscyR1cHBlciwgY29sPXBpLmNvbCwgcGNoPXN5bWJvbCwgY2V4PXNpemUpCiAgbGluZXMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGxvd2VyLCBjb2w9cGkuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKICBsaW5lcyh4PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGRlbnNpdHksIHk9cHJlZGljdGlvbi5pbnRlcnZhbHMkdXBwZXIsIGNvbD1waS5jb2wsIGx0eT1saW5lLnR5cGUsIGx3ZD1saW5lLndpZHRoKQogIAogIGxlZ2VuZCgndG9wcmlnaHQnLCBsZWdlbmQ9YygnTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uIExpbmUnLCAnOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWwgQmFuZHMnLCAnOTUlIFByZWRpY3Rpb24gSW50ZXJ2YWwgQmFuZHMnKSwgY29sPWMoJ3JlZCcsIGNpLmNvbCwgcGkuY29sKSwgbHR5PTEpCiAgCiAgcHJpbnQoUHJlZGljdERlbnNpdHlMZWFzdFNxdWFyZXMoMzguNikpICAjIDM4LjYgaXMgdGhlIGF2ZXJhZ2UgZ2FpbiBmb3IgMC41MDggZGVuc2l0eQogIHByaW50KERlbnNpdHlDaSgzOC42KSkKICBwcmludChEZW5zaXR5UGkoMzguNikpCiAgCiAgcHJpbnQoUHJlZGljdERlbnNpdHlMZWFzdFNxdWFyZXMoNDI2LjcpKSAgIyA0MjYuNyBpcyB0aGUgYXZlcmFnZSBnYWluIGZvciAwLjAwMSBkZW5zaXR5CiAgcHJpbnQoRGVuc2l0eUNpKDQyNi43KSkKICBwcmludChEZW5zaXR5UGkoNDI2LjcpKQp9CmBgYAoKCiMjIEFkZGl0aW9uYWwgU2NlbmFyaW86IFRlbXBlcmF0dXJlLCBET1ksIGFuZCBMYXRpdHVkZS4KVXNlIHRoZSBhZGRpdGlvbmFsIGRhdGFzZXQgdG8gY29uc3RydWN0IGEgbW9kZWwgZml0dGluZyB0ZW1wZXJhdHVyZSB3aXRoIERPWSwgbGF0aXR1ZGUsIGFuZCBvdGhlciByZWFzb25hYmxlIGZlYXR1cmVzLiBUcnkgc2tldGNoaW5nIHRoZSBsZWFzdCBzcXVhcmVzIGxpbmUgb24gYSBzY2F0dGVyIHBsb3QuIFdlIGFpbSB0byBpbnZlc3RpZ2F0ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGVtcGVyYXR1cmUgYW5kIHRoZSBET1ksIGFuZCBpdHMgbGF0aXR1ZGUuCmBgYHtyfQojIENoZWNrIHRoZSBjb3JyZWxhdGlvbgpkYXRhIDwtIHJlYWQuY3N2KCdGdWxsIFJlc29sdXRpb24gRGF0YS82NDUwNjQyMC5jc3YnLCBoZWFkZXI9VFJVRSkKZGF0YSA8LSBkYXRhWyxjKCdIb3VyJywnRE9ZJywnUE9TX0RPWScsJ0xhdCcsJ0xvbicsJ1RzJywnQlAnKV0KCiMgRHJvcCB0aGUgZXh0cmVtZSBvdXRsaWVyIGNhc2UKI2RhdGEgPC0gZGF0YVt3aGljaChkYXRhJFRzPi0yMDApLF0KZGF0YV9tYXRyaXggPC0gYXMubWF0cml4KGRhdGEpCgojIENvcnJlbGF0aW9uIE1hdHJpeApjb3JyX21hdHJpeCA8LSBjb3IoZGF0YV9tYXRyaXgpCmNvcnJfbWF0cml4CmBgYAoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKIyBHcm91cCBieSBET1kgYW5kIGF2ZXJhZ2UgcmVwbGljYXRlZCBtZWFzdXJlbWVudHMKZGF0YSRET1kgPC0gcm91bmQoZGF0YSRET1ksMCkKZGF0YS5hdmcgPSBhZ2dyZWdhdGUobGlzdChkYXRhPWRhdGFbLGMoJ1RzJywnTGF0JyldKSwgYnk9bGlzdChET1k9ZGF0YSRET1kpLCBGVU49bWVhbikKCiMgbGVhc3Qgc3F1YXJlcyBsaW5lCmdncGxvdChkYXRhLmF2ZyxhZXMoeD1kYXRhLmF2ZyRET1ksIHk9ZGF0YS5hdmckZGF0YS5UcykpICsgCiAgZ2VvbV9wb2ludChjb2xvcj0nIzI5ODBCOScsIHNpemUgPSA0KSArIAogIGdlb21fc21vb3RoKG1ldGhvZD1sbSwgY29sb3I9JyMyQzNFNTAnKSArZ2d0aXRsZShsYWJlbCA9IkxlYXN0IFNxdWFyZXMgUmVncmVzc2lvbiBMaW5lIikgKyB4bGFiKCJEYXkgT2YgWWVhciIpICsKICB5bGFiKCJUZW1wZXJhdHVyZSIpCmZpdDE8LWxtKGZvcm11bGEgPSBkYXRhLlRzIH4gRE9ZLCBkYXRhID0gZGF0YS5hdmcpCnN1bW1hcnkoZml0MSkKCmdncGxvdChkYXRhLmF2ZyxhZXMoeD1kYXRhLmF2ZyRkYXRhLkxhdCwgeT1kYXRhLmF2ZyRkYXRhLlRzKSkgKyAKICBnZW9tX3BvaW50KGNvbG9yPScjMjk4MEI5Jywgc2l6ZSA9IDQpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCBjb2xvcj0nIzJDM0U1MCcpICtnZ3RpdGxlKGxhYmVsID0iTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uIExpbmUiKSsgeGxhYigiTGF0dGl0dWRlIikgKwogIHlsYWIoIlRlbXBlcmF0dXJlIikKZml0MjwtbG0oZm9ybXVsYSA9IGRhdGEuVHMgfiBkYXRhLkxhdCwgZGF0YSA9IGRhdGEuYXZnKQpzdW1tYXJ5KGZpdDIpCgojIFBvbHlub21pYWwgUmVncmVzc2lvbiBMaW5lCmZpdDM8LWxtKGZvcm11bGEgPSBkYXRhLlRzIH4gRE9ZICsgZGF0YS5MYXQsIGRhdGEgPSBkYXRhLmF2ZykKZml0NDwtbG0oZm9ybXVsYSA9IGRhdGEuVHMgfiBkYXRhLkxhdCArIERPWSwgZGF0YSA9IGRhdGEuYXZnKQpzdW1tYXJ5KGZpdDMpCnN1bW1hcnkoZml0NCkKCnFxbm9ybShmaXQyJHJlc2lkdWFscywgbWFpbj1wYXN0ZSgnTm9ybWFsIFEtUSBQbG90IHdpdGgnLCB0aXRsZS5yZXNpZHVhbHMxKSwgY2V4Lm1haW49MSkKcXFsaW5lKGZpdDIkcmVzaWR1YWxzLCBjb2w9J3JlZCcpCgp0aXRsZS5yZXNpZHVhbHMxIDwtICdSZXNpZHVhbHMgb2YgTGVhc3QgU3F1YXJlIFJlZ3Jlc3Npb24gTGluZScKcGxvdChmaXQyJHJlc2lkdWFscywgbWFpbj10aXRsZS5yZXNpZHVhbHMxLCB5bGFiID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiKQphYmxpbmUoMCwgMCwgY29sPSdyZWQnKQpgYGAK
=======
LS0tCnRpdGxlOiAnQ0FTRSBTVFVEWSA0OiBDQUxJQlJBVElORyBBIFNOT1cgR0FVR0UnCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgc3R1ZHkgYWxsb3dzIHVzIHRvIHJldmlzaXQvcmVuZXcKCjEuIFJlZ3Jlc3Npb24gbW9kZWxpbmcKMi4gUHJvcGVydGllcyBvZiBMZWFzdCBTcXVhcmVzL0ZpdHRpbmcgImEgbGluZSIKMy4gTXVsdGlwbGUgb2JzZXJ2YXRpb24KCkRhdGFzZXRzIGZvciB0aGlzIHN0dWR5IGFyZQoKMS4gVGhlIG1haW4gZmlsZTogZ2F1Z2UudHh0CjIuIFN1cHBsZW1lbnRhcnkgbGFyZ2Utc2NhbGUgZmlsZXM6IGRvd25sb2FkIHRoZSBmb2xsb3dpbmcgZm9sZGVyIEZ1bGwgUmVzb2x1dGlvbiBEYXRhLnppcCBNb3JlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzdXBwbGVtZW50YXJ5IGZpbGUgY2FuIGJlIGZvdW5kIGF0IGh0dHA6Ly9pYWJwLmFwbC53YXNoaW5ndG9uLmVkdS9kYXRhLmh0bWwgYXMgd2VsbCBhcyBodHRwOi8vbnNpZGMub3JnL2RhdGEvRzAwNzkxCgoKIyMgUXVlc3Rpb24KVGhlIGFpbSBvZiB0aGlzIGxhYiBpcyB0byBwcm92aWRlIGEgc2ltcGxlIHByb2NlZHVyZSBmb3IgY29udmVydGluZyBnYWluIGludG8gZGVuc2l0eSB3aGVuIHRoZSBnYXVnZSBpcyBpbiBvcGVyYXRpb24uIEtlZXAgaW4gbWluZCB0aGF0IHRoZSBleHBlcmltZW50IHdhcyBjb25kdWN0ZWQgYnkgdmFyeWluZyBkZW5zaXR5IGFuZCBtZWFzdXJpbmcgdGhlIHJlc3BvbnNlIGluIGdhaW4sIGJ1dCB3aGVuIHRoZSBnYXVnZSBpcyB1bHRpbWF0ZWx5IGluIHVzZSwgdGhlIHNub3ctcGFjayBkZW5zaXR5IGlzIHRvIGJlIGVzdGltYXRlZCBmcm9tIHRoZSBtZWFzdXJlZCBnYWluLgoKCiMjIFNldHVwCmBgYHtyfQpkZiA8LSByZWFkLnRhYmxlKCdnYXVnZS0xd2Ixd2E2LTJncGVsNDEudHh0JywgaGVhZGVyPVRSVUUpCmRmIDwtIGRmW29yZGVyKGRmJGRlbnNpdHkpLCBdICAjIFNvcnQgZnJvbSBsZWFzdCB0byBncmVhdGVzdCBkZW5zaXR5CgptIDwtIDkgICMgTnVtYmVyIG9mIGRpc3RpbmN0IGJsb2NrIGRlbnNpdGllcwp0IDwtIDEwICAjIE51bWJlciBvZiByZXBsaWNhdGUgbWVhc3VyZW1lbnRzCgojaW5zdGFsbC5wYWNrYWdlcygnTDFwYWNrJykKI2luc3RhbGwucGFja2FnZXMoJ3F1YW50cmVnJykKI2luc3RhbGwucGFja2FnZXMoJ2dncGxvdDInKQpsaWJyYXJ5KEwxcGFjaykgICMgVXNlZCBmb3IgbGVhc3QgYWJzb2x1dGUgZGV2aWF0aW9ucyByZWdyZXNzaW9uIGxpbmUKbGlicmFyeShxdWFudHJlZykgICMgVXNlZCBmb3IgcXVhbnRpbGUgcmVncmVzc2lvbiBsaW5lCmxpYnJhcnkoZ2dwbG90MikKYGBgCgoKIyMgU2NlbmFyaW8gMTogRml0dGluZwpVc2UgdGhlIGRhdGEgdG8gZml0IHRoZSBnYWluLCBvciBhIHRyYW5zZm9ybWF0aW9uIG9mIGdhaW4sIHRvIGRlbnNpdHkuIFRyeSBza2V0Y2hpbmcgdGhlIGxlYXN0IHNxdWFyZXMgbGluZSBvbiBhIHNjYXR0ZXIgcGxvdC4KCiogRG8gdGhlIHJlc2lkdWFscyBpbmRpY2F0ZSBhbnkgcHJvYmxlbXMgd2l0aCB0aGUgZml0PwoqIElmIHRoZSBkZW5zaXRpZXMgb2YgdGhlIHBvbHlldGh5bGVuZSBibG9ja3MgYXJlIG5vdCByZXBvcnRlZCBleGFjdGx5LCBob3cgbWlnaHQgdGhpcyBhZmZlY3QgdGhlIGZpdD8KKiBXaGF0IGlmIHRoZSBibG9ja3Mgb2YgcG9seWV0aHlsZW5lIHdlcmUgbm90IG1lYXN1cmVkIGluIHJhbmRvbSBvcmRlciAobG9jYXRpb24pPwpgYGB7cn0KIyBQbG90IHJhdyBkYXRhCnRpdGxlIDwtICdEZW5zaXR5IHZzLiBHYWluJwp4LmF4aXMgPC0gZXhwcmVzc2lvbignRGVuc2l0eSAoZy9jbSdeMyonKScpCnkuYXhpcyA8LSAnR2FpbicKeC5yYW5nZSA8LSBjKDAsIC43KQp5LnJhbmdlIDwtIGMoMi41LCA2KQpwbG90KGRmLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmF4aXMsIHhsaW09eC5yYW5nZSkKCgojIFRha2UgbG9nIHRyYW5zZm9ybWF0aW9uIG9mIHJlc3BvbnNlIHZhcmlhYmxlIChnYWluKQp5LmxvZy5heGlzID0gJ2xvZyhHYWluKScKZGYubG9nID0gZGF0YS5mcmFtZShkZlsnZGVuc2l0eSddLCBsb2coZGZbJ2dhaW4nXSkpCnBsb3QoZGYubG9nLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmxvZy5heGlzLCB4bGltPXgucmFuZ2UsIHlsaW09eS5yYW5nZSkKCgojIEF2ZXJhZ2UgcmVwbGljYXRlIG1lYXN1cmVtZW50cwpkZi5sb2cuYXZnID0gYWdncmVnYXRlKGxpc3QoZ2Fpbj1kZi5sb2ckZ2FpbiksIGJ5PWxpc3QoZGVuc2l0eT1kZi5sb2ckZGVuc2l0eSksIEZVTj1tZWFuKQpwbG90KGRmLmxvZy5hdmcsIG1haW49dGl0bGUsIHhsYWI9eC5heGlzLCB5bGFiPXkubG9nLmF4aXMsIHhsaW09eC5yYW5nZSwgeWxpbT15LnJhbmdlKQoKCiMgRml0IGdhaW4gdG8gZGVuc2l0eQpsZWFzdC5zcXVhcmVzIDwtIGxtKGdhaW5+ZGVuc2l0eSwgZGF0YT1kZi5sb2cuYXZnKQpsYWQgPC0gbGFkKGdhaW5+ZGVuc2l0eSwgZGF0YT1kZi5sb2cuYXZnKQpxdWFudCA8LSBycShnYWlufmRlbnNpdHksIHRhdT0uNSwgZGF0YT1kZi5sb2cuYXZnKQoKcGxvdChkZi5sb2csIG1haW49dGl0bGUsIHhsYWI9eC5heGlzLCB5bGFiPXkubG9nLmF4aXMsIHhsaW09eC5yYW5nZSwgeWxpbT15LnJhbmdlKQphYmxpbmUobGVhc3Quc3F1YXJlcywgY29sPSdyZWQnKQphYmxpbmUobGFkLCBjb2w9J2JsdWUnKQphYmxpbmUocXVhbnQsIGNvbD0nZ3JlZW4nKQpsZWdlbmQoJ3RvcHJpZ2h0JywgbGVnZW5kPWMoJ0xlYXN0IFNxdWFyZXMgUmVncmVzc2lvbiBMaW5lJywgJ0xlYXN0IEFic29sdXRlIERldmlhdGlvbnMgUmVncmVzc2lvbiBMaW5lJywgJzUwJSBRdWFudGlsZSBSZWdyZXNzaW9uIExpbmUnKSwgY29sPWMoJ3JlZCcsICdibHVlJywgJ2dyZWVuJyksIGx0eT0xKQoKYyhjb3IoZGYubG9nLmF2ZyksIHN1bW1hcnkobGVhc3Quc3F1YXJlcykkci5zcXVhcmVkKQpsZWFzdC5zcXVhcmVzCmxhZApxdWFudAoKCiMgQ2hlY2sgY29uZGl0aW9ucyBmb3IgbGluZWFyIHJlZ3Jlc3Npb246IGxpbmVhcml0eSwgbm9ybWFsaXR5IG9mIHJlc2lkdWFscywgYW5kIGNvbnN0YW50IHZhcmlhYmlsaXR5CmxlYXN0LnNxdWFyZXMucmVzaWR1YWxzIDwtIGRhdGEuZnJhbWUoZGYubG9nWydkZW5zaXR5J10sIGRmLmxvZ1snZ2FpbiddIC0gcmVwKHByZWRpY3QobGVhc3Quc3F1YXJlcyksIGVhY2g9MTApKQpsYWQucmVzaWR1YWxzIDwtIGRhdGEuZnJhbWUoZGYubG9nWydkZW5zaXR5J10sIGRmLmxvZ1snZ2FpbiddIC0gcmVwKHByZWRpY3QobGFkKSwgZWFjaD0xMCkpCnF1YW50LnJlc2lkdWFscyA8LSBkYXRhLmZyYW1lKGRmLmxvZ1snZGVuc2l0eSddLCBkZi5sb2dbJ2dhaW4nXSAtIHJlcChwcmVkaWN0KHF1YW50KSwgZWFjaD0xMCkpCgp0aXRsZS5yZXNpZHVhbHMxIDwtICdSZXNpZHVhbHMgb2YgTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uIExpbmUnCnRpdGxlLnJlc2lkdWFsczIgPC0gJ1Jlc2lkdWFscyBvZiBMZWFzdCBBYnNvbHV0ZSBEZXZpYXRpb25zIFJlZ3Jlc3Npb24gTGluZScKdGl0bGUucmVzaWR1YWxzMyA8LSAnUmVzaWR1YWxzIG9mIDUwJSBRdWFudGlsZSBSZWdyZXNzaW9uIExpbmUnCnBsb3QobGVhc3Quc3F1YXJlcy5yZXNpZHVhbHMkZ2FpbiwgbWFpbj10aXRsZS5yZXNpZHVhbHMxLCB5bGFiPXkuYXhpcykKYWJsaW5lKDAsIDAsIGNvbD0ncmVkJykKcGxvdChsYWQucmVzaWR1YWxzJGdhaW4sIG1haW49dGl0bGUucmVzaWR1YWxzMiwgeWxhYj15LmF4aXMpCmFibGluZSgwLCAwLCBjb2w9J2JsdWUnKQpwbG90KHF1YW50LnJlc2lkdWFscyRnYWluLCBtYWluPXRpdGxlLnJlc2lkdWFsczMsIHlsYWI9eS5heGlzKQphYmxpbmUoMCwgMCwgY29sPSdncmVlbicpCgpudW0uYmlucyA8LSAxMgpoaXN0KGxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGdhaW4sIGJyZWFrcz1udW0uYmlucywgbWFpbj10aXRsZS5yZXNpZHVhbHMxLCB4bGFiPXkuYXhpcywgY29sPSdyZWQnKQpoaXN0KGxhZC5yZXNpZHVhbHMkZ2FpbiwgYnJlYWtzPW51bS5iaW5zLCBtYWluPXRpdGxlLnJlc2lkdWFsczIsIHhsYWI9eS5heGlzLCBjb2w9J2JsdWUnKQpoaXN0KHF1YW50LnJlc2lkdWFscyRnYWluLCBicmVha3M9bnVtLmJpbnMsIG1haW49dGl0bGUucmVzaWR1YWxzMywgeGxhYj15LmF4aXMsIGNvbD0nZ3JlZW4nKQoKcXFub3JtKGxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGdhaW4sIG1haW49cGFzdGUoJ05vcm1hbCBRLVEgUGxvdCB3aXRoJywgdGl0bGUucmVzaWR1YWxzMSksIGNleC5tYWluPTEpCnFxbGluZShsZWFzdC5zcXVhcmVzLnJlc2lkdWFscyRnYWluLCBjb2w9J3JlZCcpCnFxbm9ybShsYWQucmVzaWR1YWxzJGdhaW4sIG1haW49cGFzdGUoJ05vcm1hbCBRLVEgUGxvdCB3aXRoJywgdGl0bGUucmVzaWR1YWxzMiksIGNleC5tYWluPTEpCnFxbGluZShsYWQucmVzaWR1YWxzJGdhaW4sIGNvbD0nYmx1ZScpCnFxbm9ybShxdWFudC5yZXNpZHVhbHMkZ2FpbiwgbWFpbj1wYXN0ZSgnTm9ybWFsIFEtUSBQbG90IHdpdGgnLCB0aXRsZS5yZXNpZHVhbHMzKSwgY2V4Lm1haW49MSkKcXFsaW5lKHF1YW50LnJlc2lkdWFscyRnYWluLCBjb2w9J2dyZWVuJykKYGBgCgoKIyMgU2NlbmFyaW8gMjogUHJlZGljdGluZwpVbHRpbWF0ZWx5IHdlIGFyZSBpbnRlcmVzdGVkIGluIGFuc3dlcmluZyBxdWVzdGlvbnMgc3VjaCBhczogR2l2ZW4gYSBnYWluIHJlYWRpbmcgb2YgMzguNiwgd2hhdCBpcyB0aGUgZGVuc2l0eSBvZiB0aGUgc25vdy1wYWNrPyBHaXZlbiBhIGdhaW4gcmVhZGluZyBvZiA0MjYuNywgd2hhdCBpcyB0aGUgZGVuc2l0eSBvZiB0aGUgc25vdy1wYWNrPyBUaGVzZSB0d28gbnVtZXJpYyB2YWx1ZXMsIDM4LjYgYW5kIDQyNi43LCB3ZXJlIGNob3NlbiBiZWNhdXNlIHRoZXkgYXJlIHRoZSBhdmVyYWdlIGdhaW5zIGZvciB0aGUgMC41MDggYW5kIDAuMDAxIGRlbnNpdGllcywgcmVzcGVjdGl2ZWx5LgoKKiBEZXZlbG9wIGEgcHJvY2VkdXJlIGZvciBhZGRpbmcgYmFuZHMgYXJvdW5kIHlvdXIgbGVhc3Qgc3F1YXJlcyBsaW5lIHRoYXQgY2FuIGJlIHVzZWQgdG8gbWFrZSBpbnRlcnZhbCBlc3RpbWF0ZXMgZm9yIHRoZSBzbm93LXBhY2sgZGVuc2l0eSBmcm9tIGdhaW4gbWVhc3VyZW1lbnRzLiBLZWVwIGluIG1pbmQgaG93IHRoZSBkYXRhIHdlcmUgY29sbGVjdGVkOiBzZXZlcmFsIG1lYXN1cmVtZW50cyBvZiBnYWluIHdlcmUgdGFrZW4gZm9yIHBvbHllbnl0aHlsZW5lIGJsb2NrcyBvZiBrbm93biBkZW5zaXR5LgpgYGB7ciBmaWcuYXNwPTIsIGZpZy53aWR0aD01fQojIFByZWRpY3Rpb25zClByZWRpY3RMb2dHYWluIDwtIGZ1bmN0aW9uKGRlbnNpdHkpCiAgcHJlZGljdChsZWFzdC5zcXVhcmVzLCBkYXRhLmZyYW1lKGRlbnNpdHk9ZGVuc2l0eSkpICAjIFByZWRpY3QgbG9nKGdhaW4pIHVzaW5nIGRlbnNpdHkKClByZWRpY3REZW5zaXR5TGVhc3RTcXVhcmVzIDwtIGZ1bmN0aW9uKGdhaW4pIHsKICBpbnRlcmNlcHQgPC0gY29lZihsZWFzdC5zcXVhcmVzKVtbMV1dCiAgc2xvcGUgPC0gY29lZihsZWFzdC5zcXVhcmVzKVtbMl1dCiAgKGxvZyhnYWluKSAtIGludGVyY2VwdCkgLyBzbG9wZSAgIyBQcmVkaWN0IGRlbnNpdHkgdXNpbmcgZ2Fpbgp9CgpQcmVkaWN0RGVuc2l0eUxhZCA8LSBmdW5jdGlvbihnYWluKSB7CiAgaW50ZXJjZXB0IDwtIGNvZWYobGFkKVtbMV1dCiAgc2xvcGUgPC0gY29lZihsYWQpW1syXV0KICAobG9nKGdhaW4pIC0gaW50ZXJjZXB0KSAvIHNsb3BlICAjIFByZWRpY3QgZGVuc2l0eSB1c2luZyBnYWluCn0KClByZWRpY3REZW5zaXR5UXVhbnQgPC0gZnVuY3Rpb24oZ2FpbikgewogIGludGVyY2VwdCA8LSBjb2VmKHF1YW50KVtbMV1dCiAgc2xvcGUgPC0gY29lZihxdWFudClbWzJdXQogIChsb2coZ2FpbikgLSBpbnRlcmNlcHQpIC8gc2xvcGUgICMgUHJlZGljdCBkZW5zaXR5IHVzaW5nIGdhaW4KfQoKCiMgOTUlIHByZWRpY3Rpb24gYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIGxvZyhnYWluKSB1c2luZyBkZW5zaXR5CnQgPC0gcXQoLjk3NSwgZGY9bS0yKQptZWFuLmRlbnNpdHkgPC0gbWVhbihkZi5sb2cuYXZnJGRlbnNpdHkpCnN1bW1hdGlvbiA8LSBzdW0oKGRmLmxvZy5hdmckZGVuc2l0eSAtIG1lYW4uZGVuc2l0eSkgXiAyKQoKczIgPC0gYWdncmVnYXRlKGxpc3QodmFyaWFuY2U9bGVhc3Quc3F1YXJlcy5yZXNpZHVhbHMkZ2FpbiksIGJ5PWxpc3QoZGVuc2l0eT1sZWFzdC5zcXVhcmVzLnJlc2lkdWFscyRkZW5zaXR5KSwgRlVOPXZhcikKcy5wb29sZWQgPC0gc3FydChtZWFuKHMyJHZhcmlhbmNlKSkKCmNlbnRlci5leHByIDwtIHF1b3RlKGNlbnRlciA8LSBQcmVkaWN0TG9nR2FpbihkZW5zaXR5KSkKY2kud2lkdGguZXhwciA8LSBxdW90ZSh3aWR0aCA8LSB0ICogcy5wb29sZWQgKiBzcXJ0KDEvbSArIChkZW5zaXR5LW1lYW4uZGVuc2l0eSleMiAvIHN1bW1hdGlvbikpCnBpLndpZHRoLmV4cHIgPC0gcXVvdGUod2lkdGggPC0gdCAqIHMucG9vbGVkICogc3FydCgxICsgMS9tICsgKGRlbnNpdHktbWVhbi5kZW5zaXR5KV4yIC8gc3VtbWF0aW9uKSkKCkxvZ0dhaW5DaUxvd2VyIDwtIGZ1bmN0aW9uKGRlbnNpdHkpIHsKICBldmFsKGNlbnRlci5leHByKQogIGV2YWwoY2kud2lkdGguZXhwcikKICBjZW50ZXIgLSB3aWR0aAp9CgpMb2dHYWluQ2lVcHBlciA8LSBmdW5jdGlvbihkZW5zaXR5KSB7CiAgZXZhbChjZW50ZXIuZXhwcikKICBldmFsKGNpLndpZHRoLmV4cHIpCiAgY2VudGVyICsgd2lkdGgKfQoKTG9nR2FpblBpTG93ZXIgPC0gZnVuY3Rpb24oZGVuc2l0eSkgewogIGV2YWwoY2VudGVyLmV4cHIpCiAgZXZhbChwaS53aWR0aC5leHByKQogIGNlbnRlciAtIHdpZHRoCn0KCkxvZ0dhaW5QaVVwcGVyIDwtIGZ1bmN0aW9uKGRlbnNpdHkpIHsKICBldmFsKGNlbnRlci5leHByKQogIGV2YWwocGkud2lkdGguZXhwcikKICBjZW50ZXIgKyB3aWR0aAp9CgojIEFkZCBiYW5kcyBhcm91bmQgbGVhc3Qgc3F1YXJlcyBsaW5lCnBsb3QoZGYubG9nLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmxvZy5heGlzLCB4bGltPXgucmFuZ2UsIHlsaW09eS5yYW5nZSkKYWJsaW5lKGxlYXN0LnNxdWFyZXMsIGNvbD0ncmVkJykKCmNpLmNvbCA8LSAncHVycGxlJwpwaS5jb2wgPC0gJ2JsdWUnCnN5bWJvbCA8LSAnLScKc2l6ZSA8LSAxLjUKbGluZS50eXBlIDwtIDMKbGluZS53aWR0aCA8LSAwLjcKCmNvbmZpZGVuY2UuaW50ZXJ2YWxzIDwtIGRhdGEuZnJhbWUoZGVuc2l0eT1kZi5sb2cuYXZnJGRlbnNpdHksIGxvd2VyPUxvZ0dhaW5DaUxvd2VyKGRmLmxvZy5hdmckZGVuc2l0eSksIHVwcGVyPUxvZ0dhaW5DaVVwcGVyKGRmLmxvZy5hdmckZGVuc2l0eSkpCnBvaW50cyh4PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGRlbnNpdHksIHk9Y29uZmlkZW5jZS5pbnRlcnZhbHMkbG93ZXIsIGNvbD1jaS5jb2wsIHBjaD1zeW1ib2wsIGNleD1zaXplKQpwb2ludHMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJHVwcGVyLCBjb2w9Y2kuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKbGluZXMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGxvd2VyLCBjb2w9Y2kuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKbGluZXMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJHVwcGVyLCBjb2w9Y2kuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKCnByZWRpY3Rpb24uaW50ZXJ2YWxzIDwtIGRhdGEuZnJhbWUoZGVuc2l0eT1kZi5sb2cuYXZnJGRlbnNpdHksIGxvd2VyPUxvZ0dhaW5QaUxvd2VyKGRmLmxvZy5hdmckZGVuc2l0eSksIHVwcGVyPUxvZ0dhaW5QaVVwcGVyKGRmLmxvZy5hdmckZGVuc2l0eSkpCnBvaW50cyh4PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGRlbnNpdHksIHk9cHJlZGljdGlvbi5pbnRlcnZhbHMkbG93ZXIsIGNvbD1waS5jb2wsIHBjaD1zeW1ib2wsIGNleD1zaXplKQpwb2ludHMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJHVwcGVyLCBjb2w9cGkuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKbGluZXMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGxvd2VyLCBjb2w9cGkuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKbGluZXMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJHVwcGVyLCBjb2w9cGkuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKCmxlZ2VuZCgndG9wcmlnaHQnLCBsZWdlbmQ9YygnTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uIExpbmUnLCAnOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWwgQmFuZHMnLCAnOTUlIFByZWRpY3Rpb24gSW50ZXJ2YWwgQmFuZHMnKSwgY29sPWMoJ3JlZCcsIGNpLmNvbCwgcGkuY29sKSwgbHR5PTEpCgoKIyA5NSUgcHJlZGljdGlvbiBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMgb2YgZGVuc2l0eSB1c2luZyBnYWluCmVuZC5wb2ludHMgPC0gYygtMSwgMykgICMgSW50ZXJ2YWwgdG8gc2VhcmNoIHRoZSByb290IGluCgpEZW5zaXR5Q2kgPC0gZnVuY3Rpb24oZ2FpbikgewogIGxvd2VyIDwtIHVuaXJvb3QoZnVuY3Rpb24oZGVuc2l0eSkgbG9nKGdhaW4pIC0gTG9nR2FpbkNpTG93ZXIoZGVuc2l0eSksIGludGVydmFsPWVuZC5wb2ludHMpW1sxXV0KICB1cHBlciA8LSB1bmlyb290KGZ1bmN0aW9uKGRlbnNpdHkpIGxvZyhnYWluKSAtIExvZ0dhaW5DaVVwcGVyKGRlbnNpdHkpLCBpbnRlcnZhbD1lbmQucG9pbnRzKVtbMV1dCiAgYyhsb3dlciwgdXBwZXIpCn0KCkRlbnNpdHlQaSA8LSBmdW5jdGlvbihnYWluKSB7CiAgbG93ZXIgPC0gdW5pcm9vdChmdW5jdGlvbihkZW5zaXR5KSBsb2coZ2FpbikgLSBMb2dHYWluUGlMb3dlcihkZW5zaXR5KSwgZW5kLnBvaW50cylbWzFdXQogIHVwcGVyIDwtIHVuaXJvb3QoZnVuY3Rpb24oZGVuc2l0eSkgbG9nKGdhaW4pIC0gTG9nR2FpblBpVXBwZXIoZGVuc2l0eSksIGVuZC5wb2ludHMpW1sxXV0KICBjKGxvd2VyLCB1cHBlcikKfQoKCiMgUG9pbnQgYW5kIGludGVydmFsIGVzdGltYXRlcyBmb3IgZXhhbXBsZSBnYWluIHJlYWRpbmdzClByZWRpY3REZW5zaXR5TGVhc3RTcXVhcmVzKDM4LjYpICAjIDM4LjYgaXMgdGhlIGF2ZXJhZ2UgZ2FpbiBmb3IgMC41MDggZGVuc2l0eQpQcmVkaWN0RGVuc2l0eUxhZCgzOC42KQpQcmVkaWN0RGVuc2l0eVF1YW50KDM4LjYpCkRlbnNpdHlDaSgzOC42KQpEZW5zaXR5UGkoMzguNikKClByZWRpY3REZW5zaXR5TGVhc3RTcXVhcmVzKDQyNi43KSAgIyA0MjYuNyBpcyB0aGUgYXZlcmFnZSBnYWluIGZvciAwLjAwMSBkZW5zaXR5ClByZWRpY3REZW5zaXR5TGFkKDQyNi43KQpQcmVkaWN0RGVuc2l0eVF1YW50KDQyNi43KQpEZW5zaXR5Q2koNDI2LjcpCkRlbnNpdHlQaSg0MjYuNykKYGBgCgoKIyMgU2NlbmFyaW8gMzogQ3Jvc3MtVmFsaWRhdGlvbgpUbyBjaGVjayBob3cgd2VsbCB5b3VyIHByb2NlZHVyZSB3b3Jrcywgb21pdCB0aGUgc2V0IG9mIG1lYXN1cmVtZW50cyBjb3JyZXNwb25kaW5nIHRvIHRoZSBibG9jayBvZiBkZW5zaXR5IDAuNTA4LCBhcHBseSB5b3VyICJlc3RpbWF0aW9uIi9jYWxpYnJhdGlvbiBwcm9jZWR1cmUgdG8gdGhlIHJlbWFpbmluZyBkYXRhLCBhbmQgcHJvdmlkZSBhbiBpbnRlcnZhbCBlc3RpbWF0ZSBmb3IgdGhlIGRlbnNpdHkgb2YgYSBibG9jayB3aXRoIGFuIGF2ZXJhZ2UgcmVhZGluZyBvZiAzOC42LiBXaGVyZSBkb2VzIHRoZSBhY3R1YWwgZGVuc2l0eSBmYWxsIGluIHRoZSBpbnRlcnZhbD8gVHJ5IHRoZSBzYW1lIHRlc3QsIGZvciB0aGUgc2V0IG9mIG1lYXN1cmVtZW50cyBhdCB0aGUgMC4wMDEgZGVuc2l0eS4KYGBge3IgZmlnLmFzcD0yLCBmaWcud2lkdGg9NX0KZm9yIChvbWl0dGVkIGluIGMoMC41MDgsIDAuMDAxKSkgewogICMgT21pdCBtZWFzdXJlbWVudHMgY29ycmVzcG9uZGluZyB0byB0aGUgc3BlY2lmaWVkIGRlbnNpdHkKICBkZi5sb2cub21pdHRlZCA9IGRmLmxvZ1t3aGljaChkZi5sb2dbJ2RlbnNpdHknXSAhPSBvbWl0dGVkKSwgXQogIGRmLmxvZy5hdmcub21pdHRlZCA8LSBkZi5sb2cuYXZnW3doaWNoKGRmLmxvZy5hdmdbJ2RlbnNpdHknXSAhPSBvbWl0dGVkKSwgXQogIAogIAogICMgUmVkbyBjYWxjdWxhdGlvbnMgdXNpbmcgbW9kaWZpZWQgZGF0YXNldAogIGxlYXN0LnNxdWFyZXMgPC0gbG0oZ2Fpbn5kZW5zaXR5LCBkYXRhPWRmLmxvZy5hdmcub21pdHRlZCkKICAKICBtZWFuLmRlbnNpdHkgPC0gbWVhbihkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSkKICBzdW1tYXRpb24gPC0gc3VtKChkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSAtIG1lYW4uZGVuc2l0eSkgXiAyKQogIAogIHMyIDwtIGFnZ3JlZ2F0ZShsaXN0KHZhcmlhbmNlPWxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGdhaW4pLCBieT1saXN0KGRlbnNpdHk9bGVhc3Quc3F1YXJlcy5yZXNpZHVhbHMkZGVuc2l0eSksIEZVTj12YXIpCiAgcy5wb29sZWQgPC0gc3FydChtZWFuKHMyJHZhcmlhbmNlKSkKICAKICBjaS53aWR0aC5leHByIDwtIHF1b3RlKHdpZHRoIDwtIHQgKiBzLnBvb2xlZCAqIHNxcnQoMS8obS0xKSArIChkZW5zaXR5LW1lYW4uZGVuc2l0eSleMiAvIHN1bW1hdGlvbikpCiAgcGkud2lkdGguZXhwciA8LSBxdW90ZSh3aWR0aCA8LSB0ICogcy5wb29sZWQgKiBzcXJ0KDEgKyAxLyhtLTEpICsgKGRlbnNpdHktbWVhbi5kZW5zaXR5KV4yIC8gc3VtbWF0aW9uKSkKICAKICBwbG90KGRmLmxvZy5vbWl0dGVkLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmxvZy5heGlzLCB4bGltPXgucmFuZ2UsIHlsaW09eS5yYW5nZSkKICBhYmxpbmUobGVhc3Quc3F1YXJlcywgY29sPSdyZWQnKQogIAogIGNpLmNvbCA8LSAncHVycGxlJwogIHBpLmNvbCA8LSAnYmx1ZScKICBzeW1ib2wgPC0gJy0nCiAgc2l6ZSA8LSAxLjUKICBsaW5lLnR5cGUgPC0gMwogIGxpbmUud2lkdGggPC0gMC43CiAgCiAgY29uZmlkZW5jZS5pbnRlcnZhbHMgPC0gZGF0YS5mcmFtZShkZW5zaXR5PWRmLmxvZy5hdmcub21pdHRlZCRkZW5zaXR5LCBsb3dlcj1Mb2dHYWluQ2lMb3dlcihkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSksIHVwcGVyPUxvZ0dhaW5DaVVwcGVyKGRmLmxvZy5hdmcub21pdHRlZCRkZW5zaXR5KSkKICBwb2ludHMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGxvd2VyLCBjb2w9Y2kuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKICBwb2ludHMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJHVwcGVyLCBjb2w9Y2kuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKICBsaW5lcyh4PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGRlbnNpdHksIHk9Y29uZmlkZW5jZS5pbnRlcnZhbHMkbG93ZXIsIGNvbD1jaS5jb2wsIGx0eT1saW5lLnR5cGUsIGx3ZD1saW5lLndpZHRoKQogIGxpbmVzKHg9Y29uZmlkZW5jZS5pbnRlcnZhbHMkZGVuc2l0eSwgeT1jb25maWRlbmNlLmludGVydmFscyR1cHBlciwgY29sPWNpLmNvbCwgbHR5PWxpbmUudHlwZSwgbHdkPWxpbmUud2lkdGgpCiAgCiAgcHJlZGljdGlvbi5pbnRlcnZhbHMgPC0gZGF0YS5mcmFtZShkZW5zaXR5PWRmLmxvZy5hdmcub21pdHRlZCRkZW5zaXR5LCBsb3dlcj1Mb2dHYWluUGlMb3dlcihkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSksIHVwcGVyPUxvZ0dhaW5QaVVwcGVyKGRmLmxvZy5hdmcub21pdHRlZCRkZW5zaXR5KSkKICBwb2ludHMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGxvd2VyLCBjb2w9cGkuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKICBwb2ludHMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJHVwcGVyLCBjb2w9cGkuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKICBsaW5lcyh4PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGRlbnNpdHksIHk9cHJlZGljdGlvbi5pbnRlcnZhbHMkbG93ZXIsIGNvbD1waS5jb2wsIGx0eT1saW5lLnR5cGUsIGx3ZD1saW5lLndpZHRoKQogIGxpbmVzKHg9cHJlZGljdGlvbi5pbnRlcnZhbHMkZGVuc2l0eSwgeT1wcmVkaWN0aW9uLmludGVydmFscyR1cHBlciwgY29sPXBpLmNvbCwgbHR5PWxpbmUudHlwZSwgbHdkPWxpbmUud2lkdGgpCiAgCiAgbGVnZW5kKCd0b3ByaWdodCcsIGxlZ2VuZD1jKCdMZWFzdCBTcXVhcmVzIFJlZ3Jlc3Npb24gTGluZScsICc5NSUgQ29uZmlkZW5jZSBJbnRlcnZhbCBCYW5kcycsICc5NSUgUHJlZGljdGlvbiBJbnRlcnZhbCBCYW5kcycpLCBjb2w9YygncmVkJywgY2kuY29sLCBwaS5jb2wpLCBsdHk9MSkKICAKICBwcmludChQcmVkaWN0RGVuc2l0eUxlYXN0U3F1YXJlcygzOC42KSkgICMgMzguNiBpcyB0aGUgYXZlcmFnZSBnYWluIGZvciAwLjUwOCBkZW5zaXR5CiAgcHJpbnQoRGVuc2l0eUNpKDM4LjYpKQogIHByaW50KERlbnNpdHlQaSgzOC42KSkKICAKICBwcmludChQcmVkaWN0RGVuc2l0eUxlYXN0U3F1YXJlcyg0MjYuNykpICAjIDQyNi43IGlzIHRoZSBhdmVyYWdlIGdhaW4gZm9yIDAuMDAxIGRlbnNpdHkKICBwcmludChEZW5zaXR5Q2koNDI2LjcpKQogIHByaW50KERlbnNpdHlQaSg0MjYuNykpCn0KYGBgCgoKIyMgQWRkaXRpb25hbCBTY2VuYXJpbzogVGVtcGVyYXR1cmUsIERPWSwgYW5kIExhdGl0dWRlLgpVc2UgdGhlIGFkZGl0aW9uYWwgZGF0YXNldCB0byBjb25zdHJ1Y3QgYSBtb2RlbCBmaXR0aW5nIHRlbXBlcmF0dXJlIHdpdGggRE9ZLCBsYXRpdHVkZSwgYW5kIG90aGVyIHJlYXNvbmFibGUgZmVhdHVyZXMuIFRyeSBza2V0Y2hpbmcgdGhlIGxlYXN0IHNxdWFyZXMgbGluZSBvbiBhIHNjYXR0ZXIgcGxvdC4gV2UgYWltIHRvIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0ZW1wZXJhdHVyZSBhbmQgdGhlIERPWSwgYW5kIGl0cyBsYXRpdHVkZS4KYGBge3J9CiMgQ2hlY2sgdGhlIGNvcnJlbGF0aW9uCmRhdGEgPC0gcmVhZC5jc3YoJ0Z1bGwgUmVzb2x1dGlvbiBEYXRhLzY0NTA2NDIwLmNzdicsIGhlYWRlcj1UUlVFKQpkYXRhIDwtIGRhdGFbLGMoJ0hvdXInLCdET1knLCdQT1NfRE9ZJywnTGF0JywnTG9uJywnVHMnLCdCUCcpXQoKIyBEcm9wIHRoZSBleHRyZW1lIG91dGxpZXIgY2FzZQojZGF0YSA8LSBkYXRhW3doaWNoKGRhdGEkVHM+LTIwMCksXQpkYXRhX21hdHJpeCA8LSBhcy5tYXRyaXgoZGF0YSkKCiMgQ29ycmVsYXRpb24gTWF0cml4CmNvcnJfbWF0cml4IDwtIGNvcihkYXRhX21hdHJpeCkKY29ycl9tYXRyaXgKYGBgCgpgYGB7cn0KIyBHcm91cCBieSBET1kgYW5kIGF2ZXJhZ2UgcmVwbGljYXRlZCBtZWFzdXJlbWVudHMKZGF0YSRET1kgPC0gcm91bmQoZGF0YSRET1ksMCkKZGF0YS5hdmcgPSBhZ2dyZWdhdGUobGlzdChkYXRhPWRhdGFbLGMoJ1RzJywnTGF0JyldKSwgYnk9bGlzdChET1k9ZGF0YSRET1kpLCBGVU49bWVhbikKCiMgbGVhc3Qgc3F1YXJlcyBsaW5lCmdncGxvdChkYXRhLmF2ZyxhZXMoeD1kYXRhLmF2ZyRET1ksIHk9ZGF0YS5hdmckZGF0YS5UcykpICsgCiAgZ2VvbV9wb2ludChjb2xvcj0nIzI5ODBCOScsIHNpemUgPSA0KSArIAogIGdlb21fc21vb3RoKG1ldGhvZD1sbSwgY29sb3I9JyMyQzNFNTAnKSArZ2d0aXRsZShsYWJlbCA9IkxlYXN0IFNxdWFyZXMgUmVncmVzc2lvbiBMaW5lIikgKyB4bGFiKCJEYXkgT2YgWWVhciIpICsKICB5bGFiKCJUZW1wZXJhdHVyZSIpCmZpdDE8LWxtKGZvcm11bGEgPSBkYXRhLlRzIH4gRE9ZLCBkYXRhID0gZGF0YS5hdmcpCnN1bW1hcnkoZml0MSkKCmdncGxvdChkYXRhLmF2ZyxhZXMoeD1kYXRhLmF2ZyRkYXRhLkxhdCwgeT1kYXRhLmF2ZyRkYXRhLlRzKSkgKyAKICBnZW9tX3BvaW50KGNvbG9yPScjMjk4MEI5Jywgc2l6ZSA9IDQpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCBjb2xvcj0nIzJDM0U1MCcpICtnZ3RpdGxlKGxhYmVsID0iTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uIExpbmUiKSsgeGxhYigiTGF0dGl0dWRlIikgKwogIHlsYWIoIlRlbXBlcmF0dXJlIikKZml0MjwtbG0oZm9ybXVsYSA9IGRhdGEuVHMgfiBkYXRhLkxhdCwgZGF0YSA9IGRhdGEuYXZnKQpzdW1tYXJ5KGZpdDIpCgojIFBvbHlub21pYWwgUmVncmVzc2lvbiBMaW5lCmZpdDM8LWxtKGZvcm11bGEgPSBkYXRhLlRzIH4gRE9ZICsgZGF0YS5MYXQsIGRhdGEgPSBkYXRhLmF2ZykKc3VtbWFyeShmaXQzKQoKcXFub3JtKGZpdDIkcmVzaWR1YWxzLCBtYWluPXBhc3RlKCdOb3JtYWwgUS1RIFBsb3Qgd2l0aCcsIHRpdGxlLnJlc2lkdWFsczEpLCBjZXgubWFpbj0xKQpxcWxpbmUoZml0MiRyZXNpZHVhbHMsIGNvbD0ncmVkJykKCnRpdGxlLnJlc2lkdWFsczEgPC0gJ1Jlc2lkdWFscyBvZiBMZWFzdCBTcXVhcmUgUmVncmVzc2lvbiBMaW5lJwpwbG90KGZpdDIkcmVzaWR1YWxzLCBtYWluPXRpdGxlLnJlc2lkdWFsczEsIHlsYWIgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIpCmFibGluZSgwLCAwLCBjb2w9J3JlZCcpCmBgYA==
>>>>>>> a218eb53d4e1304da795c118b0f05e05e3489cdd =======
LS0tCnRpdGxlOiAnQ0FTRSBTVFVEWSA0OiBDQUxJQlJBVElORyBBIFNOT1cgR0FVR0UnCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgc3R1ZHkgYWxsb3dzIHVzIHRvIHJldmlzaXQvcmVuZXcKCjEuIFJlZ3Jlc3Npb24gbW9kZWxpbmcKMi4gUHJvcGVydGllcyBvZiBMZWFzdCBTcXVhcmVzL0ZpdHRpbmcgImEgbGluZSIKMy4gTXVsdGlwbGUgb2JzZXJ2YXRpb24KCkRhdGFzZXRzIGZvciB0aGlzIHN0dWR5IGFyZQoKMS4gVGhlIG1haW4gZmlsZTogZ2F1Z2UudHh0CjIuIFN1cHBsZW1lbnRhcnkgbGFyZ2Utc2NhbGUgZmlsZXM6IGRvd25sb2FkIHRoZSBmb2xsb3dpbmcgZm9sZGVyIEZ1bGwgUmVzb2x1dGlvbiBEYXRhLnppcCBNb3JlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzdXBwbGVtZW50YXJ5IGZpbGUgY2FuIGJlIGZvdW5kIGF0IGh0dHA6Ly9pYWJwLmFwbC53YXNoaW5ndG9uLmVkdS9kYXRhLmh0bWwgYXMgd2VsbCBhcyBodHRwOi8vbnNpZGMub3JnL2RhdGEvRzAwNzkxCgoKIyMgUXVlc3Rpb24KVGhlIGFpbSBvZiB0aGlzIGxhYiBpcyB0byBwcm92aWRlIGEgc2ltcGxlIHByb2NlZHVyZSBmb3IgY29udmVydGluZyBnYWluIGludG8gZGVuc2l0eSB3aGVuIHRoZSBnYXVnZSBpcyBpbiBvcGVyYXRpb24uIEtlZXAgaW4gbWluZCB0aGF0IHRoZSBleHBlcmltZW50IHdhcyBjb25kdWN0ZWQgYnkgdmFyeWluZyBkZW5zaXR5IGFuZCBtZWFzdXJpbmcgdGhlIHJlc3BvbnNlIGluIGdhaW4sIGJ1dCB3aGVuIHRoZSBnYXVnZSBpcyB1bHRpbWF0ZWx5IGluIHVzZSwgdGhlIHNub3ctcGFjayBkZW5zaXR5IGlzIHRvIGJlIGVzdGltYXRlZCBmcm9tIHRoZSBtZWFzdXJlZCBnYWluLgoKCiMjIFNldHVwCmBgYHtyfQpkZiA8LSByZWFkLnRhYmxlKCdnYXVnZS0xd2Ixd2E2LTJncGVsNDEudHh0JywgaGVhZGVyPVRSVUUpCmRmIDwtIGRmW29yZGVyKGRmJGRlbnNpdHkpLCBdICAjIFNvcnQgZnJvbSBsZWFzdCB0byBncmVhdGVzdCBkZW5zaXR5CgptIDwtIDkgICMgTnVtYmVyIG9mIGRpc3RpbmN0IGJsb2NrIGRlbnNpdGllcwp0IDwtIDEwICAjIE51bWJlciBvZiByZXBsaWNhdGUgbWVhc3VyZW1lbnRzCgojaW5zdGFsbC5wYWNrYWdlcygnTDFwYWNrJykKI2luc3RhbGwucGFja2FnZXMoJ3F1YW50cmVnJykKI2luc3RhbGwucGFja2FnZXMoJ2dncGxvdDInKQpsaWJyYXJ5KEwxcGFjaykgICMgVXNlZCBmb3IgbGVhc3QgYWJzb2x1dGUgZGV2aWF0aW9ucyByZWdyZXNzaW9uIGxpbmUKbGlicmFyeShxdWFudHJlZykgICMgVXNlZCBmb3IgcXVhbnRpbGUgcmVncmVzc2lvbiBsaW5lCmxpYnJhcnkoZ2dwbG90MikKYGBgCgoKIyMgU2NlbmFyaW8gMTogRml0dGluZwpVc2UgdGhlIGRhdGEgdG8gZml0IHRoZSBnYWluLCBvciBhIHRyYW5zZm9ybWF0aW9uIG9mIGdhaW4sIHRvIGRlbnNpdHkuIFRyeSBza2V0Y2hpbmcgdGhlIGxlYXN0IHNxdWFyZXMgbGluZSBvbiBhIHNjYXR0ZXIgcGxvdC4KCiogRG8gdGhlIHJlc2lkdWFscyBpbmRpY2F0ZSBhbnkgcHJvYmxlbXMgd2l0aCB0aGUgZml0PwoqIElmIHRoZSBkZW5zaXRpZXMgb2YgdGhlIHBvbHlldGh5bGVuZSBibG9ja3MgYXJlIG5vdCByZXBvcnRlZCBleGFjdGx5LCBob3cgbWlnaHQgdGhpcyBhZmZlY3QgdGhlIGZpdD8KKiBXaGF0IGlmIHRoZSBibG9ja3Mgb2YgcG9seWV0aHlsZW5lIHdlcmUgbm90IG1lYXN1cmVkIGluIHJhbmRvbSBvcmRlciAobG9jYXRpb24pPwpgYGB7cn0KIyBQbG90IHJhdyBkYXRhCnRpdGxlIDwtICdEZW5zaXR5IHZzLiBHYWluJwp4LmF4aXMgPC0gZXhwcmVzc2lvbignRGVuc2l0eSAoZy9jbSdeMyonKScpCnkuYXhpcyA8LSAnR2FpbicKeC5yYW5nZSA8LSBjKDAsIC43KQp5LnJhbmdlIDwtIGMoMi41LCA2KQpwbG90KGRmLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmF4aXMsIHhsaW09eC5yYW5nZSkKCgojIFRha2UgbG9nIHRyYW5zZm9ybWF0aW9uIG9mIHJlc3BvbnNlIHZhcmlhYmxlIChnYWluKQp5LmxvZy5heGlzID0gJ2xvZyhHYWluKScKZGYubG9nID0gZGF0YS5mcmFtZShkZlsnZGVuc2l0eSddLCBsb2coZGZbJ2dhaW4nXSkpCnBsb3QoZGYubG9nLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmxvZy5heGlzLCB4bGltPXgucmFuZ2UsIHlsaW09eS5yYW5nZSkKCgojIEF2ZXJhZ2UgcmVwbGljYXRlIG1lYXN1cmVtZW50cwpkZi5sb2cuYXZnID0gYWdncmVnYXRlKGxpc3QoZ2Fpbj1kZi5sb2ckZ2FpbiksIGJ5PWxpc3QoZGVuc2l0eT1kZi5sb2ckZGVuc2l0eSksIEZVTj1tZWFuKQpwbG90KGRmLmxvZy5hdmcsIG1haW49dGl0bGUsIHhsYWI9eC5heGlzLCB5bGFiPXkubG9nLmF4aXMsIHhsaW09eC5yYW5nZSwgeWxpbT15LnJhbmdlKQoKCiMgRml0IGdhaW4gdG8gZGVuc2l0eQpsZWFzdC5zcXVhcmVzIDwtIGxtKGdhaW5+ZGVuc2l0eSwgZGF0YT1kZi5sb2cuYXZnKQpsYWQgPC0gbGFkKGdhaW5+ZGVuc2l0eSwgZGF0YT1kZi5sb2cuYXZnKQpxdWFudCA8LSBycShnYWlufmRlbnNpdHksIHRhdT0uNSwgZGF0YT1kZi5sb2cuYXZnKQoKcGxvdChkZi5sb2csIG1haW49dGl0bGUsIHhsYWI9eC5heGlzLCB5bGFiPXkubG9nLmF4aXMsIHhsaW09eC5yYW5nZSwgeWxpbT15LnJhbmdlKQphYmxpbmUobGVhc3Quc3F1YXJlcywgY29sPSdyZWQnKQphYmxpbmUobGFkLCBjb2w9J2JsdWUnKQphYmxpbmUocXVhbnQsIGNvbD0nZ3JlZW4nKQpsZWdlbmQoJ3RvcHJpZ2h0JywgbGVnZW5kPWMoJ0xlYXN0IFNxdWFyZXMgUmVncmVzc2lvbiBMaW5lJywgJ0xlYXN0IEFic29sdXRlIERldmlhdGlvbnMgUmVncmVzc2lvbiBMaW5lJywgJzUwJSBRdWFudGlsZSBSZWdyZXNzaW9uIExpbmUnKSwgY29sPWMoJ3JlZCcsICdibHVlJywgJ2dyZWVuJyksIGx0eT0xKQoKYyhjb3IoZGYubG9nLmF2ZyksIHN1bW1hcnkobGVhc3Quc3F1YXJlcykkci5zcXVhcmVkKQpsZWFzdC5zcXVhcmVzCmxhZApxdWFudAoKCiMgQ2hlY2sgY29uZGl0aW9ucyBmb3IgbGluZWFyIHJlZ3Jlc3Npb246IGxpbmVhcml0eSwgbm9ybWFsaXR5IG9mIHJlc2lkdWFscywgYW5kIGNvbnN0YW50IHZhcmlhYmlsaXR5CmxlYXN0LnNxdWFyZXMucmVzaWR1YWxzIDwtIGRhdGEuZnJhbWUoZGYubG9nWydkZW5zaXR5J10sIGRmLmxvZ1snZ2FpbiddIC0gcmVwKHByZWRpY3QobGVhc3Quc3F1YXJlcyksIGVhY2g9MTApKQpsYWQucmVzaWR1YWxzIDwtIGRhdGEuZnJhbWUoZGYubG9nWydkZW5zaXR5J10sIGRmLmxvZ1snZ2FpbiddIC0gcmVwKHByZWRpY3QobGFkKSwgZWFjaD0xMCkpCnF1YW50LnJlc2lkdWFscyA8LSBkYXRhLmZyYW1lKGRmLmxvZ1snZGVuc2l0eSddLCBkZi5sb2dbJ2dhaW4nXSAtIHJlcChwcmVkaWN0KHF1YW50KSwgZWFjaD0xMCkpCgp0aXRsZS5yZXNpZHVhbHMxIDwtICdSZXNpZHVhbHMgb2YgTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uIExpbmUnCnRpdGxlLnJlc2lkdWFsczIgPC0gJ1Jlc2lkdWFscyBvZiBMZWFzdCBBYnNvbHV0ZSBEZXZpYXRpb25zIFJlZ3Jlc3Npb24gTGluZScKdGl0bGUucmVzaWR1YWxzMyA8LSAnUmVzaWR1YWxzIG9mIDUwJSBRdWFudGlsZSBSZWdyZXNzaW9uIExpbmUnCnBsb3QobGVhc3Quc3F1YXJlcy5yZXNpZHVhbHMkZ2FpbiwgbWFpbj10aXRsZS5yZXNpZHVhbHMxLCB5bGFiPXkuYXhpcykKYWJsaW5lKDAsIDAsIGNvbD0ncmVkJykKcGxvdChsYWQucmVzaWR1YWxzJGdhaW4sIG1haW49dGl0bGUucmVzaWR1YWxzMiwgeWxhYj15LmF4aXMpCmFibGluZSgwLCAwLCBjb2w9J2JsdWUnKQpwbG90KHF1YW50LnJlc2lkdWFscyRnYWluLCBtYWluPXRpdGxlLnJlc2lkdWFsczMsIHlsYWI9eS5heGlzKQphYmxpbmUoMCwgMCwgY29sPSdncmVlbicpCgpudW0uYmlucyA8LSAxMgpoaXN0KGxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGdhaW4sIGJyZWFrcz1udW0uYmlucywgbWFpbj10aXRsZS5yZXNpZHVhbHMxLCB4bGFiPXkuYXhpcywgY29sPSdyZWQnKQpoaXN0KGxhZC5yZXNpZHVhbHMkZ2FpbiwgYnJlYWtzPW51bS5iaW5zLCBtYWluPXRpdGxlLnJlc2lkdWFsczIsIHhsYWI9eS5heGlzLCBjb2w9J2JsdWUnKQpoaXN0KHF1YW50LnJlc2lkdWFscyRnYWluLCBicmVha3M9bnVtLmJpbnMsIG1haW49dGl0bGUucmVzaWR1YWxzMywgeGxhYj15LmF4aXMsIGNvbD0nZ3JlZW4nKQoKcXFub3JtKGxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGdhaW4sIG1haW49cGFzdGUoJ05vcm1hbCBRLVEgUGxvdCB3aXRoJywgdGl0bGUucmVzaWR1YWxzMSksIGNleC5tYWluPTEpCnFxbGluZShsZWFzdC5zcXVhcmVzLnJlc2lkdWFscyRnYWluLCBjb2w9J3JlZCcpCnFxbm9ybShsYWQucmVzaWR1YWxzJGdhaW4sIG1haW49cGFzdGUoJ05vcm1hbCBRLVEgUGxvdCB3aXRoJywgdGl0bGUucmVzaWR1YWxzMiksIGNleC5tYWluPTEpCnFxbGluZShsYWQucmVzaWR1YWxzJGdhaW4sIGNvbD0nYmx1ZScpCnFxbm9ybShxdWFudC5yZXNpZHVhbHMkZ2FpbiwgbWFpbj1wYXN0ZSgnTm9ybWFsIFEtUSBQbG90IHdpdGgnLCB0aXRsZS5yZXNpZHVhbHMzKSwgY2V4Lm1haW49MSkKcXFsaW5lKHF1YW50LnJlc2lkdWFscyRnYWluLCBjb2w9J2dyZWVuJykKYGBgCgoKIyMgU2NlbmFyaW8gMjogUHJlZGljdGluZwpVbHRpbWF0ZWx5IHdlIGFyZSBpbnRlcmVzdGVkIGluIGFuc3dlcmluZyBxdWVzdGlvbnMgc3VjaCBhczogR2l2ZW4gYSBnYWluIHJlYWRpbmcgb2YgMzguNiwgd2hhdCBpcyB0aGUgZGVuc2l0eSBvZiB0aGUgc25vdy1wYWNrPyBHaXZlbiBhIGdhaW4gcmVhZGluZyBvZiA0MjYuNywgd2hhdCBpcyB0aGUgZGVuc2l0eSBvZiB0aGUgc25vdy1wYWNrPyBUaGVzZSB0d28gbnVtZXJpYyB2YWx1ZXMsIDM4LjYgYW5kIDQyNi43LCB3ZXJlIGNob3NlbiBiZWNhdXNlIHRoZXkgYXJlIHRoZSBhdmVyYWdlIGdhaW5zIGZvciB0aGUgMC41MDggYW5kIDAuMDAxIGRlbnNpdGllcywgcmVzcGVjdGl2ZWx5LgoKKiBEZXZlbG9wIGEgcHJvY2VkdXJlIGZvciBhZGRpbmcgYmFuZHMgYXJvdW5kIHlvdXIgbGVhc3Qgc3F1YXJlcyBsaW5lIHRoYXQgY2FuIGJlIHVzZWQgdG8gbWFrZSBpbnRlcnZhbCBlc3RpbWF0ZXMgZm9yIHRoZSBzbm93LXBhY2sgZGVuc2l0eSBmcm9tIGdhaW4gbWVhc3VyZW1lbnRzLiBLZWVwIGluIG1pbmQgaG93IHRoZSBkYXRhIHdlcmUgY29sbGVjdGVkOiBzZXZlcmFsIG1lYXN1cmVtZW50cyBvZiBnYWluIHdlcmUgdGFrZW4gZm9yIHBvbHllbnl0aHlsZW5lIGJsb2NrcyBvZiBrbm93biBkZW5zaXR5LgpgYGB7ciBmaWcuYXNwPTIsIGZpZy53aWR0aD01fQojIFByZWRpY3Rpb25zClByZWRpY3RMb2dHYWluIDwtIGZ1bmN0aW9uKGRlbnNpdHkpCiAgcHJlZGljdChsZWFzdC5zcXVhcmVzLCBkYXRhLmZyYW1lKGRlbnNpdHk9ZGVuc2l0eSkpICAjIFByZWRpY3QgbG9nKGdhaW4pIHVzaW5nIGRlbnNpdHkKClByZWRpY3REZW5zaXR5TGVhc3RTcXVhcmVzIDwtIGZ1bmN0aW9uKGdhaW4pIHsKICBpbnRlcmNlcHQgPC0gY29lZihsZWFzdC5zcXVhcmVzKVtbMV1dCiAgc2xvcGUgPC0gY29lZihsZWFzdC5zcXVhcmVzKVtbMl1dCiAgKGxvZyhnYWluKSAtIGludGVyY2VwdCkgLyBzbG9wZSAgIyBQcmVkaWN0IGRlbnNpdHkgdXNpbmcgZ2Fpbgp9CgpQcmVkaWN0RGVuc2l0eUxhZCA8LSBmdW5jdGlvbihnYWluKSB7CiAgaW50ZXJjZXB0IDwtIGNvZWYobGFkKVtbMV1dCiAgc2xvcGUgPC0gY29lZihsYWQpW1syXV0KICAobG9nKGdhaW4pIC0gaW50ZXJjZXB0KSAvIHNsb3BlICAjIFByZWRpY3QgZGVuc2l0eSB1c2luZyBnYWluCn0KClByZWRpY3REZW5zaXR5UXVhbnQgPC0gZnVuY3Rpb24oZ2FpbikgewogIGludGVyY2VwdCA8LSBjb2VmKHF1YW50KVtbMV1dCiAgc2xvcGUgPC0gY29lZihxdWFudClbWzJdXQogIChsb2coZ2FpbikgLSBpbnRlcmNlcHQpIC8gc2xvcGUgICMgUHJlZGljdCBkZW5zaXR5IHVzaW5nIGdhaW4KfQoKCiMgOTUlIHByZWRpY3Rpb24gYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIGxvZyhnYWluKSB1c2luZyBkZW5zaXR5CnQgPC0gcXQoLjk3NSwgZGY9bS0yKQptZWFuLmRlbnNpdHkgPC0gbWVhbihkZi5sb2cuYXZnJGRlbnNpdHkpCnN1bW1hdGlvbiA8LSBzdW0oKGRmLmxvZy5hdmckZGVuc2l0eSAtIG1lYW4uZGVuc2l0eSkgXiAyKQoKczIgPC0gYWdncmVnYXRlKGxpc3QodmFyaWFuY2U9bGVhc3Quc3F1YXJlcy5yZXNpZHVhbHMkZ2FpbiksIGJ5PWxpc3QoZGVuc2l0eT1sZWFzdC5zcXVhcmVzLnJlc2lkdWFscyRkZW5zaXR5KSwgRlVOPXZhcikKcy5wb29sZWQgPC0gc3FydChtZWFuKHMyJHZhcmlhbmNlKSkKCmNlbnRlci5leHByIDwtIHF1b3RlKGNlbnRlciA8LSBQcmVkaWN0TG9nR2FpbihkZW5zaXR5KSkKY2kud2lkdGguZXhwciA8LSBxdW90ZSh3aWR0aCA8LSB0ICogcy5wb29sZWQgKiBzcXJ0KDEvbSArIChkZW5zaXR5LW1lYW4uZGVuc2l0eSleMiAvIHN1bW1hdGlvbikpCnBpLndpZHRoLmV4cHIgPC0gcXVvdGUod2lkdGggPC0gdCAqIHMucG9vbGVkICogc3FydCgxICsgMS9tICsgKGRlbnNpdHktbWVhbi5kZW5zaXR5KV4yIC8gc3VtbWF0aW9uKSkKCkxvZ0dhaW5DaUxvd2VyIDwtIGZ1bmN0aW9uKGRlbnNpdHkpIHsKICBldmFsKGNlbnRlci5leHByKQogIGV2YWwoY2kud2lkdGguZXhwcikKICBjZW50ZXIgLSB3aWR0aAp9CgpMb2dHYWluQ2lVcHBlciA8LSBmdW5jdGlvbihkZW5zaXR5KSB7CiAgZXZhbChjZW50ZXIuZXhwcikKICBldmFsKGNpLndpZHRoLmV4cHIpCiAgY2VudGVyICsgd2lkdGgKfQoKTG9nR2FpblBpTG93ZXIgPC0gZnVuY3Rpb24oZGVuc2l0eSkgewogIGV2YWwoY2VudGVyLmV4cHIpCiAgZXZhbChwaS53aWR0aC5leHByKQogIGNlbnRlciAtIHdpZHRoCn0KCkxvZ0dhaW5QaVVwcGVyIDwtIGZ1bmN0aW9uKGRlbnNpdHkpIHsKICBldmFsKGNlbnRlci5leHByKQogIGV2YWwocGkud2lkdGguZXhwcikKICBjZW50ZXIgKyB3aWR0aAp9CgojIEFkZCBiYW5kcyBhcm91bmQgbGVhc3Qgc3F1YXJlcyBsaW5lCnBsb3QoZGYubG9nLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmxvZy5heGlzLCB4bGltPXgucmFuZ2UsIHlsaW09eS5yYW5nZSkKYWJsaW5lKGxlYXN0LnNxdWFyZXMsIGNvbD0ncmVkJykKCmNpLmNvbCA8LSAncHVycGxlJwpwaS5jb2wgPC0gJ2JsdWUnCnN5bWJvbCA8LSAnLScKc2l6ZSA8LSAxLjUKbGluZS50eXBlIDwtIDMKbGluZS53aWR0aCA8LSAwLjcKCmNvbmZpZGVuY2UuaW50ZXJ2YWxzIDwtIGRhdGEuZnJhbWUoZGVuc2l0eT1kZi5sb2cuYXZnJGRlbnNpdHksIGxvd2VyPUxvZ0dhaW5DaUxvd2VyKGRmLmxvZy5hdmckZGVuc2l0eSksIHVwcGVyPUxvZ0dhaW5DaVVwcGVyKGRmLmxvZy5hdmckZGVuc2l0eSkpCnBvaW50cyh4PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGRlbnNpdHksIHk9Y29uZmlkZW5jZS5pbnRlcnZhbHMkbG93ZXIsIGNvbD1jaS5jb2wsIHBjaD1zeW1ib2wsIGNleD1zaXplKQpwb2ludHMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJHVwcGVyLCBjb2w9Y2kuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKbGluZXMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGxvd2VyLCBjb2w9Y2kuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKbGluZXMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJHVwcGVyLCBjb2w9Y2kuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKCnByZWRpY3Rpb24uaW50ZXJ2YWxzIDwtIGRhdGEuZnJhbWUoZGVuc2l0eT1kZi5sb2cuYXZnJGRlbnNpdHksIGxvd2VyPUxvZ0dhaW5QaUxvd2VyKGRmLmxvZy5hdmckZGVuc2l0eSksIHVwcGVyPUxvZ0dhaW5QaVVwcGVyKGRmLmxvZy5hdmckZGVuc2l0eSkpCnBvaW50cyh4PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGRlbnNpdHksIHk9cHJlZGljdGlvbi5pbnRlcnZhbHMkbG93ZXIsIGNvbD1waS5jb2wsIHBjaD1zeW1ib2wsIGNleD1zaXplKQpwb2ludHMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJHVwcGVyLCBjb2w9cGkuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKbGluZXMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGxvd2VyLCBjb2w9cGkuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKbGluZXMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJHVwcGVyLCBjb2w9cGkuY29sLCBsdHk9bGluZS50eXBlLCBsd2Q9bGluZS53aWR0aCkKCmxlZ2VuZCgndG9wcmlnaHQnLCBsZWdlbmQ9YygnTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uIExpbmUnLCAnOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWwgQmFuZHMnLCAnOTUlIFByZWRpY3Rpb24gSW50ZXJ2YWwgQmFuZHMnKSwgY29sPWMoJ3JlZCcsIGNpLmNvbCwgcGkuY29sKSwgbHR5PTEpCgoKIyA5NSUgcHJlZGljdGlvbiBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMgb2YgZGVuc2l0eSB1c2luZyBnYWluCmVuZC5wb2ludHMgPC0gYygtMSwgMykgICMgSW50ZXJ2YWwgdG8gc2VhcmNoIHRoZSByb290IGluCgpEZW5zaXR5Q2kgPC0gZnVuY3Rpb24oZ2FpbikgewogIGxvd2VyIDwtIHVuaXJvb3QoZnVuY3Rpb24oZGVuc2l0eSkgbG9nKGdhaW4pIC0gTG9nR2FpbkNpTG93ZXIoZGVuc2l0eSksIGludGVydmFsPWVuZC5wb2ludHMpW1sxXV0KICB1cHBlciA8LSB1bmlyb290KGZ1bmN0aW9uKGRlbnNpdHkpIGxvZyhnYWluKSAtIExvZ0dhaW5DaVVwcGVyKGRlbnNpdHkpLCBpbnRlcnZhbD1lbmQucG9pbnRzKVtbMV1dCiAgYyhsb3dlciwgdXBwZXIpCn0KCkRlbnNpdHlQaSA8LSBmdW5jdGlvbihnYWluKSB7CiAgbG93ZXIgPC0gdW5pcm9vdChmdW5jdGlvbihkZW5zaXR5KSBsb2coZ2FpbikgLSBMb2dHYWluUGlMb3dlcihkZW5zaXR5KSwgZW5kLnBvaW50cylbWzFdXQogIHVwcGVyIDwtIHVuaXJvb3QoZnVuY3Rpb24oZGVuc2l0eSkgbG9nKGdhaW4pIC0gTG9nR2FpblBpVXBwZXIoZGVuc2l0eSksIGVuZC5wb2ludHMpW1sxXV0KICBjKGxvd2VyLCB1cHBlcikKfQoKCiMgUG9pbnQgYW5kIGludGVydmFsIGVzdGltYXRlcyBmb3IgZXhhbXBsZSBnYWluIHJlYWRpbmdzClByZWRpY3REZW5zaXR5TGVhc3RTcXVhcmVzKDM4LjYpICAjIDM4LjYgaXMgdGhlIGF2ZXJhZ2UgZ2FpbiBmb3IgMC41MDggZGVuc2l0eQpQcmVkaWN0RGVuc2l0eUxhZCgzOC42KQpQcmVkaWN0RGVuc2l0eVF1YW50KDM4LjYpCkRlbnNpdHlDaSgzOC42KQpEZW5zaXR5UGkoMzguNikKClByZWRpY3REZW5zaXR5TGVhc3RTcXVhcmVzKDQyNi43KSAgIyA0MjYuNyBpcyB0aGUgYXZlcmFnZSBnYWluIGZvciAwLjAwMSBkZW5zaXR5ClByZWRpY3REZW5zaXR5TGFkKDQyNi43KQpQcmVkaWN0RGVuc2l0eVF1YW50KDQyNi43KQpEZW5zaXR5Q2koNDI2LjcpCkRlbnNpdHlQaSg0MjYuNykKYGBgCgoKIyMgU2NlbmFyaW8gMzogQ3Jvc3MtVmFsaWRhdGlvbgpUbyBjaGVjayBob3cgd2VsbCB5b3VyIHByb2NlZHVyZSB3b3Jrcywgb21pdCB0aGUgc2V0IG9mIG1lYXN1cmVtZW50cyBjb3JyZXNwb25kaW5nIHRvIHRoZSBibG9jayBvZiBkZW5zaXR5IDAuNTA4LCBhcHBseSB5b3VyICJlc3RpbWF0aW9uIi9jYWxpYnJhdGlvbiBwcm9jZWR1cmUgdG8gdGhlIHJlbWFpbmluZyBkYXRhLCBhbmQgcHJvdmlkZSBhbiBpbnRlcnZhbCBlc3RpbWF0ZSBmb3IgdGhlIGRlbnNpdHkgb2YgYSBibG9jayB3aXRoIGFuIGF2ZXJhZ2UgcmVhZGluZyBvZiAzOC42LiBXaGVyZSBkb2VzIHRoZSBhY3R1YWwgZGVuc2l0eSBmYWxsIGluIHRoZSBpbnRlcnZhbD8gVHJ5IHRoZSBzYW1lIHRlc3QsIGZvciB0aGUgc2V0IG9mIG1lYXN1cmVtZW50cyBhdCB0aGUgMC4wMDEgZGVuc2l0eS4KYGBge3IgZmlnLmFzcD0yLCBmaWcud2lkdGg9NX0KZm9yIChvbWl0dGVkIGluIGMoMC41MDgsIDAuMDAxKSkgewogICMgT21pdCBtZWFzdXJlbWVudHMgY29ycmVzcG9uZGluZyB0byB0aGUgc3BlY2lmaWVkIGRlbnNpdHkKICBkZi5sb2cub21pdHRlZCA9IGRmLmxvZ1t3aGljaChkZi5sb2dbJ2RlbnNpdHknXSAhPSBvbWl0dGVkKSwgXQogIGRmLmxvZy5hdmcub21pdHRlZCA8LSBkZi5sb2cuYXZnW3doaWNoKGRmLmxvZy5hdmdbJ2RlbnNpdHknXSAhPSBvbWl0dGVkKSwgXQogIAogIAogICMgUmVkbyBjYWxjdWxhdGlvbnMgdXNpbmcgbW9kaWZpZWQgZGF0YXNldAogIGxlYXN0LnNxdWFyZXMgPC0gbG0oZ2Fpbn5kZW5zaXR5LCBkYXRhPWRmLmxvZy5hdmcub21pdHRlZCkKICAKICBtZWFuLmRlbnNpdHkgPC0gbWVhbihkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSkKICBzdW1tYXRpb24gPC0gc3VtKChkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSAtIG1lYW4uZGVuc2l0eSkgXiAyKQogIAogIHMyIDwtIGFnZ3JlZ2F0ZShsaXN0KHZhcmlhbmNlPWxlYXN0LnNxdWFyZXMucmVzaWR1YWxzJGdhaW4pLCBieT1saXN0KGRlbnNpdHk9bGVhc3Quc3F1YXJlcy5yZXNpZHVhbHMkZGVuc2l0eSksIEZVTj12YXIpCiAgcy5wb29sZWQgPC0gc3FydChtZWFuKHMyJHZhcmlhbmNlKSkKICAKICBjaS53aWR0aC5leHByIDwtIHF1b3RlKHdpZHRoIDwtIHQgKiBzLnBvb2xlZCAqIHNxcnQoMS8obS0xKSArIChkZW5zaXR5LW1lYW4uZGVuc2l0eSleMiAvIHN1bW1hdGlvbikpCiAgcGkud2lkdGguZXhwciA8LSBxdW90ZSh3aWR0aCA8LSB0ICogcy5wb29sZWQgKiBzcXJ0KDEgKyAxLyhtLTEpICsgKGRlbnNpdHktbWVhbi5kZW5zaXR5KV4yIC8gc3VtbWF0aW9uKSkKICAKICBwbG90KGRmLmxvZy5vbWl0dGVkLCBtYWluPXRpdGxlLCB4bGFiPXguYXhpcywgeWxhYj15LmxvZy5heGlzLCB4bGltPXgucmFuZ2UsIHlsaW09eS5yYW5nZSkKICBhYmxpbmUobGVhc3Quc3F1YXJlcywgY29sPSdyZWQnKQogIAogIGNpLmNvbCA8LSAncHVycGxlJwogIHBpLmNvbCA8LSAnYmx1ZScKICBzeW1ib2wgPC0gJy0nCiAgc2l6ZSA8LSAxLjUKICBsaW5lLnR5cGUgPC0gMwogIGxpbmUud2lkdGggPC0gMC43CiAgCiAgY29uZmlkZW5jZS5pbnRlcnZhbHMgPC0gZGF0YS5mcmFtZShkZW5zaXR5PWRmLmxvZy5hdmcub21pdHRlZCRkZW5zaXR5LCBsb3dlcj1Mb2dHYWluQ2lMb3dlcihkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSksIHVwcGVyPUxvZ0dhaW5DaVVwcGVyKGRmLmxvZy5hdmcub21pdHRlZCRkZW5zaXR5KSkKICBwb2ludHMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGxvd2VyLCBjb2w9Y2kuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKICBwb2ludHMoeD1jb25maWRlbmNlLmludGVydmFscyRkZW5zaXR5LCB5PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJHVwcGVyLCBjb2w9Y2kuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKICBsaW5lcyh4PWNvbmZpZGVuY2UuaW50ZXJ2YWxzJGRlbnNpdHksIHk9Y29uZmlkZW5jZS5pbnRlcnZhbHMkbG93ZXIsIGNvbD1jaS5jb2wsIGx0eT1saW5lLnR5cGUsIGx3ZD1saW5lLndpZHRoKQogIGxpbmVzKHg9Y29uZmlkZW5jZS5pbnRlcnZhbHMkZGVuc2l0eSwgeT1jb25maWRlbmNlLmludGVydmFscyR1cHBlciwgY29sPWNpLmNvbCwgbHR5PWxpbmUudHlwZSwgbHdkPWxpbmUud2lkdGgpCiAgCiAgcHJlZGljdGlvbi5pbnRlcnZhbHMgPC0gZGF0YS5mcmFtZShkZW5zaXR5PWRmLmxvZy5hdmcub21pdHRlZCRkZW5zaXR5LCBsb3dlcj1Mb2dHYWluUGlMb3dlcihkZi5sb2cuYXZnLm9taXR0ZWQkZGVuc2l0eSksIHVwcGVyPUxvZ0dhaW5QaVVwcGVyKGRmLmxvZy5hdmcub21pdHRlZCRkZW5zaXR5KSkKICBwb2ludHMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGxvd2VyLCBjb2w9cGkuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKICBwb2ludHMoeD1wcmVkaWN0aW9uLmludGVydmFscyRkZW5zaXR5LCB5PXByZWRpY3Rpb24uaW50ZXJ2YWxzJHVwcGVyLCBjb2w9cGkuY29sLCBwY2g9c3ltYm9sLCBjZXg9c2l6ZSkKICBsaW5lcyh4PXByZWRpY3Rpb24uaW50ZXJ2YWxzJGRlbnNpdHksIHk9cHJlZGljdGlvbi5pbnRlcnZhbHMkbG93ZXIsIGNvbD1waS5jb2wsIGx0eT1saW5lLnR5cGUsIGx3ZD1saW5lLndpZHRoKQogIGxpbmVzKHg9cHJlZGljdGlvbi5pbnRlcnZhbHMkZGVuc2l0eSwgeT1wcmVkaWN0aW9uLmludGVydmFscyR1cHBlciwgY29sPXBpLmNvbCwgbHR5PWxpbmUudHlwZSwgbHdkPWxpbmUud2lkdGgpCiAgCiAgbGVnZW5kKCd0b3ByaWdodCcsIGxlZ2VuZD1jKCdMZWFzdCBTcXVhcmVzIFJlZ3Jlc3Npb24gTGluZScsICc5NSUgQ29uZmlkZW5jZSBJbnRlcnZhbCBCYW5kcycsICc5NSUgUHJlZGljdGlvbiBJbnRlcnZhbCBCYW5kcycpLCBjb2w9YygncmVkJywgY2kuY29sLCBwaS5jb2wpLCBsdHk9MSkKICAKICBwcmludChQcmVkaWN0RGVuc2l0eUxlYXN0U3F1YXJlcygzOC42KSkgICMgMzguNiBpcyB0aGUgYXZlcmFnZSBnYWluIGZvciAwLjUwOCBkZW5zaXR5CiAgcHJpbnQoRGVuc2l0eUNpKDM4LjYpKQogIHByaW50KERlbnNpdHlQaSgzOC42KSkKICAKICBwcmludChQcmVkaWN0RGVuc2l0eUxlYXN0U3F1YXJlcyg0MjYuNykpICAjIDQyNi43IGlzIHRoZSBhdmVyYWdlIGdhaW4gZm9yIDAuMDAxIGRlbnNpdHkKICBwcmludChEZW5zaXR5Q2koNDI2LjcpKQogIHByaW50KERlbnNpdHlQaSg0MjYuNykpCn0KYGBgCgoKIyMgQWRkaXRpb25hbCBTY2VuYXJpbzogVGVtcGVyYXR1cmUsIERPWSwgYW5kIExhdGl0dWRlLgpVc2UgdGhlIGFkZGl0aW9uYWwgZGF0YXNldCB0byBjb25zdHJ1Y3QgYSBtb2RlbCBmaXR0aW5nIHRlbXBlcmF0dXJlIHdpdGggRE9ZLCBsYXRpdHVkZSwgYW5kIG90aGVyIHJlYXNvbmFibGUgZmVhdHVyZXMuIFRyeSBza2V0Y2hpbmcgdGhlIGxlYXN0IHNxdWFyZXMgbGluZSBvbiBhIHNjYXR0ZXIgcGxvdC4gV2UgYWltIHRvIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0ZW1wZXJhdHVyZSBhbmQgdGhlIERPWSwgYW5kIGl0cyBsYXRpdHVkZS4KYGBge3J9CiMgQ2hlY2sgdGhlIGNvcnJlbGF0aW9uCmRhdGEgPC0gcmVhZC5jc3YoJ0Z1bGwgUmVzb2x1dGlvbiBEYXRhLzY0NTA2NDIwLmNzdicsIGhlYWRlcj1UUlVFKQpkYXRhIDwtIGRhdGFbLGMoJ0hvdXInLCdET1knLCdQT1NfRE9ZJywnTGF0JywnTG9uJywnVHMnLCdCUCcpXQoKIyBEcm9wIHRoZSBleHRyZW1lIG91dGxpZXIgY2FzZQojZGF0YSA8LSBkYXRhW3doaWNoKGRhdGEkVHM+LTIwMCksXQpkYXRhX21hdHJpeCA8LSBhcy5tYXRyaXgoZGF0YSkKCiMgQ29ycmVsYXRpb24gTWF0cml4CmNvcnJfbWF0cml4IDwtIGNvcihkYXRhX21hdHJpeCkKY29ycl9tYXRyaXgKYGBgCgpgYGB7cn0KIyBHcm91cCBieSBET1kgYW5kIGF2ZXJhZ2UgcmVwbGljYXRlZCBtZWFzdXJlbWVudHMKZGF0YSRET1kgPC0gcm91bmQoZGF0YSRET1ksMCkKZGF0YS5hdmcgPSBhZ2dyZWdhdGUobGlzdChkYXRhPWRhdGFbLGMoJ1RzJywnTGF0JyldKSwgYnk9bGlzdChET1k9ZGF0YSRET1kpLCBGVU49bWVhbikKCiMgbGVhc3Qgc3F1YXJlcyBsaW5lCmdncGxvdChkYXRhLmF2ZyxhZXMoeD1kYXRhLmF2ZyRET1ksIHk9ZGF0YS5hdmckZGF0YS5UcykpICsgCiAgZ2VvbV9wb2ludChjb2xvcj0nIzI5ODBCOScsIHNpemUgPSA0KSArIAogIGdlb21fc21vb3RoKG1ldGhvZD1sbSwgY29sb3I9JyMyQzNFNTAnKSArZ2d0aXRsZShsYWJlbCA9IkxlYXN0IFNxdWFyZXMgUmVncmVzc2lvbiBMaW5lIikgKyB4bGFiKCJEYXkgT2YgWWVhciIpICsKICB5bGFiKCJUZW1wZXJhdHVyZSIpCmZpdDE8LWxtKGZvcm11bGEgPSBkYXRhLlRzIH4gRE9ZLCBkYXRhID0gZGF0YS5hdmcpCnN1bW1hcnkoZml0MSkKCmdncGxvdChkYXRhLmF2ZyxhZXMoeD1kYXRhLmF2ZyRkYXRhLkxhdCwgeT1kYXRhLmF2ZyRkYXRhLlRzKSkgKyAKICBnZW9tX3BvaW50KGNvbG9yPScjMjk4MEI5Jywgc2l6ZSA9IDQpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCBjb2xvcj0nIzJDM0U1MCcpICtnZ3RpdGxlKGxhYmVsID0iTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uIExpbmUiKSsgeGxhYigiTGF0dGl0dWRlIikgKwogIHlsYWIoIlRlbXBlcmF0dXJlIikKZml0MjwtbG0oZm9ybXVsYSA9IGRhdGEuVHMgfiBkYXRhLkxhdCwgZGF0YSA9IGRhdGEuYXZnKQpzdW1tYXJ5KGZpdDIpCgojIFBvbHlub21pYWwgUmVncmVzc2lvbiBMaW5lCmZpdDM8LWxtKGZvcm11bGEgPSBkYXRhLlRzIH4gRE9ZICsgZGF0YS5MYXQsIGRhdGEgPSBkYXRhLmF2ZykKc3VtbWFyeShmaXQzKQoKcXFub3JtKGZpdDIkcmVzaWR1YWxzLCBtYWluPXBhc3RlKCdOb3JtYWwgUS1RIFBsb3Qgd2l0aCcsIHRpdGxlLnJlc2lkdWFsczEpLCBjZXgubWFpbj0xKQpxcWxpbmUoZml0MiRyZXNpZHVhbHMsIGNvbD0ncmVkJykKCnRpdGxlLnJlc2lkdWFsczEgPC0gJ1Jlc2lkdWFscyBvZiBMZWFzdCBTcXVhcmUgUmVncmVzc2lvbiBMaW5lJwpwbG90KGZpdDIkcmVzaWR1YWxzLCBtYWluPXRpdGxlLnJlc2lkdWFsczEsIHlsYWIgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIpCmFibGluZSgwLCAwLCBjb2w9J3JlZCcpCmBgYA==
>>>>>>> 204edf09b64812dd3419f7d0197823c9debedf5b